【问题标题】:PHP : Get private key from a single line private keyPHP:从单行私钥获取私钥
【发布时间】:2019-12-05 12:31:29
【问题描述】:

我正在尝试创建一个JWT 令牌。另一台服务器将公钥存储在一行中并使用它进行验证。

另外,用于验证的公钥是单行的。

所以,要生成正确的 JWT 令牌,我认为我还应该在一行中使用私钥(可能带有 \n 或可能没有)。

我正在使用openssl_sign 生成令牌,它使用openssl_reource 作为密钥。我从openssl_pkey_get_private 得到那个参数。

但在这种情况下发生的问题是,它要么接受pem 文件路径,要么接受PEM 字符串格式的密钥。因此,如果我将 private_key 作为单行传递,它不会给我所需的输出。

那么,我该如何解决这个问题。正如我看到的其他语言库能够通过在一行中传递私钥来生成签名。

【问题讨论】:

    标签: php openssl rsa


    【解决方案1】:

    在 PHP 中,密钥可以使用换行符或单行格式(使用\n)。两者都有效。在以下示例中,为了简单起见,我使用了 512 位加密的 RSA 密钥(尽管出于安全原因,实际上必须使用更大的密钥(>= 2048 位)):

    <?php
    
    // Private key: 512 bit for simplicity
    // Passphrase: MyPassphrase
    // openssl genrsa -aes256 -out private.pem 512
    $privKeyEnc = "-----BEGIN RSA PRIVATE KEY-----
    Proc-Type: 4,ENCRYPTED
    DEK-Info: AES-256-CBC,8F2D6F9594B3D379BF9D9748BD174458
    
    RP2fyz1VNBKHiCadC5B9fjxV7z7AMAqbsN2vykFfPhdUFsxlJaecEeTMT7s6IbZN
    Pr80+ljLjJ0SxJiK+j8DAc/Wrf+qyYUFcWbsvOhUIPyB5ww9+mEeIERJCigsyZJ7
    k/Apau/BypdC9vCXKB3wM9FcmvP1g/ZwVoXfN3TIPEfWTktvuf74yFNoIaVbZAK/
    +tzAGduu9wLkr6WTq4Isqy/IPjVCp9VwH1wNnz+hjkO7oELcCpFieIvAidUMKBR9
    EdexLQCimbOl2wlfRNLincK8+FDOVWx6ElFFQlhzyWQCt8ed1fdiAggKxOco4Ww2
    tFjIzaO4KXlbc9JFGd9PzigpftN/aHbk3c+x0E+3q5u8eySai4vgk38s1KaE7rn/
    rarCgtGxOlbbTkI3opkjIrGlrsEyexKtS23mI/Dgcco=
    -----END RSA PRIVATE KEY-----";
    
    // One-liner using \n
    $privKeyEnc_1Line = "-----BEGIN RSA PRIVATE KEY-----\nProc-Type: 4,ENCRYPTED\nDEK-Info: AES-256-CBC,8F2D6F9594B3D379BF9D9748BD174458\n\nRP2fyz1VNBKHiCadC5B9fjxV7z7AMAqbsN2vykFfPhdUFsxlJaecEeTMT7s6IbZN\nPr80+ljLjJ0SxJiK+j8DAc/Wrf+qyYUFcWbsvOhUIPyB5ww9+mEeIERJCigsyZJ7\nk/Apau/BypdC9vCXKB3wM9FcmvP1g/ZwVoXfN3TIPEfWTktvuf74yFNoIaVbZAK/\n+tzAGduu9wLkr6WTq4Isqy/IPjVCp9VwH1wNnz+hjkO7oELcCpFieIvAidUMKBR9\nEdexLQCimbOl2wlfRNLincK8+FDOVWx6ElFFQlhzyWQCt8ed1fdiAggKxOco4Ww2\ntFjIzaO4KXlbc9JFGd9PzigpftN/aHbk3c+x0E+3q5u8eySai4vgk38s1KaE7rn/\nrarCgtGxOlbbTkI3opkjIrGlrsEyexKtS23mI/Dgcco=\n-----END RSA PRIVATE KEY-----";
    
    // Public key: 
    // Passphrase: MyPassphrase
    // openssl rsa -in private.pem -outform PEM -pubout -out public.pem
    $pubKey = "-----BEGIN PUBLIC KEY-----
    MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAMjYQLbdIVgKX1mSyKijOIpmlB9YWui1
    KoCniRNHUPEsxth+o9fZXZMo1gzh9ZlFs6VLiyU7kv2+5QElOnhNzwcCAwEAAQ==
    -----END PUBLIC KEY-----";
    
    // One-liner using \n
    $pubKey_1Line = "-----BEGIN PUBLIC KEY-----\nMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAMjYQLbdIVgKX1mSyKijOIpmlB9YWui1\nKoCniRNHUPEsxth+o9fZXZMo1gzh9ZlFs6VLiyU7kv2+5QElOnhNzwcCAwEAAQ==\n-----END PUBLIC KEY-----";
    
    $dataToSign = 'The quick brown fox jumps over the lazy dog.';
    
    // Signing
    //$privateKey = openssl_pkey_get_private("$privKeyEnc", "MyPassphrase");     // also works
    $privateKey = openssl_pkey_get_private("$privKeyEnc_1Line", "MyPassphrase"); 
    openssl_sign($dataToSign, $signature, $privateKey, 'sha256'); 
    $signatureBase64 = base64_encode($signature);
    print("Signature (Base64): ".$signatureBase64."<br>");
    
    // Verifying
    $publicKey = openssl_pkey_get_public("$pubKey");                             
    //$publicKey = openssl_pkey_get_public("$pubKey_1Line");                     // also works
    $verified = openssl_verify($dataToSign, $signature, $publicKey,'sha256');
    print("Verification: ".$verified."<br>");
    
    /*
    Output:
    Signature (Base64): KVuUd+xy6at0emmhF20rbiD9lWzIN9euwKbeEm7aMvxqEkJ68HrjAoDJ37R3QGPI24woXY3TON9pahAhx+YNhQ==
    Verification: 1
    */
    
    ?>
    

    【讨论】:

    • 我们可以通过删除头部和尾部来生成吗?因为我目前的要求是唯一的,但 openssl 需要 header 和 tail。
    • openssl_pkey_get_private 需要 PEM 格式的密钥。 PEM format 有页眉和页脚,因此 OpenSSL 两者都需要。但即使您只有 PEM 密钥的正文,您也可以轻松添加页眉和页脚。还是您的密钥格式不同?也许我误解了这个问题。
    • 感谢您的回复。我会重申我的问题。我的 jwt 令牌得到验证的外部服务器考虑到应该在没有页眉和页脚的情况下生成一个令牌。但正如你所说,我们的功能只能在那种格式下工作。那么,在 php 域中,有没有办法做到这一点?
    • 密钥的页眉和页脚不包含影响加密的任何信息,即它们仅标识密钥格式。您可能在DER format 中使用没有页眉和页脚的键。如果是这种情况,必须首先将密钥转换为 PEM 格式,以便它们可以用于 openssl 功能。也许验证问题根本不是由密钥引起的。
    • 是的,这实际上是有道理的。页眉和页脚仅用于解析。我使用ssh-keygen -t rsa -b 4096 -m PEM -f private.key 生成了密钥,但肯定有其他原因导致验证问题,而不是您所说的。
    猜你喜欢
    • 1970-01-01
    • 2021-05-08
    • 2014-02-16
    • 1970-01-01
    • 2017-09-20
    • 2012-01-02
    • 1970-01-01
    • 1970-01-01
    • 2011-11-05
    相关资源
    最近更新 更多