蔡蔡小棉袄 發表於 2019-11-12 17:53:00

Java & PHP RSA 互通密钥、签名、验签、加密、解密

<p>RSA加密算法是一种非对称加密算法。在公开密钥加密和电子商业中RSA被广泛使用。RSA是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的。当时他们三人都在麻省理工学院工作。RSA就是他们三人姓氏开头字母拼在一起组成的。</p>
<p>RSA是第一个比较完善的公开密钥算法,它既能用于加密,也能用于数字签名。这个算法经受住了多年深入的密码分析,虽然密码分析者既不能证明也不能否定RSA的安全性,但这恰恰说明该算法有一定的可信性,目前它已经成为最流行的公开密钥算法。</p>
<p>RSA的安全基于大数分解的难度。其公钥和私钥是一对大素数(100到200位十进制数或更大)的函数。从一个公钥和密文恢复出明文的难度,等价于分解两个大素数之积(这是公认的数学难题)。</p>
<p>RSA的公钥、私钥的组成,以及加密、解密的公式可见于下表:</p>
<p><img src="###thio47-1-png###" alt="" loading="lazy"></p>
<h1 id="版本">版本</h1>
<table>
<thead>
<tr>
<th style="text-align: center">语言</th>
<th style="text-align: center">版本</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center">PHP</td>
<td style="text-align: center">7.3.11</td>
</tr>
<tr>
<td style="text-align: center">Java</td>
<td style="text-align: center">1.8.0_231</td>
</tr>
</tbody>
</table>
<h1 id="密钥生成">密钥生成</h1>
<h2 id="php">PHP</h2>
<p><strong>RSAUtils::resetGenKeyPair</strong></p>
<pre><code class="language-php">public static function resetGenKeyPair()
{
        $config = array(
                "private_key_bits" =&gt; self::PRIVATE_KEY_BITS,
                "private_key_type" =&gt; self::KEY_ALGORITHM,
        );

        $openssl = openssl_pkey_new($config);
        openssl_pkey_export($openssl, $privateKey);
        $publicKey = openssl_pkey_get_details($openssl);
        $publicKey = $publicKey["key"];

        return [
                'publicKey'   =&gt; $publicKey,
                'privateKey'    =&gt; $privateKey,
                'publicKeyStr'=&gt; self::key2str($publicKey),
                'privateKeyStr' =&gt; self::key2str($privateKey)
        ];
}
</code></pre>
<h2 id="java">Java</h2>
<p><strong>RSAUtils.resetGenKeyPair</strong></p>
<pre><code class="language-Java">static Map&lt;String, Object&gt; resetGenKeyPair() throws Exception {
    KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
    keyPairGen.initialize(1024);

    KeyPair keyPair            = keyPairGen.generateKeyPair();
    RSAPublicKey publicKey   = (RSAPublicKey) keyPair.getPublic();
    RSAPrivateKey privateKey   = (RSAPrivateKey) keyPair.getPrivate();
    Map&lt;String, Object&gt; keyMap = new HashMap&lt;String, Object&gt;(2);

    keyMap.put(PUBLIC_KEY, publicKey);
    keyMap.put(PRIVATE_KEY, privateKey);
    return keyMap;
}
</code></pre>
<h1 id="签名">签名</h1>
<p>私钥加签。</p>
<p>有时签名可能会因为数据编码不同而导致不一致,所以要求 PHP 和 Java 都对数据进行编码处理。</p>
<h2 id="php-1">PHP</h2>
<p><strong>RSAUtils::sign</strong></p>
<pre><code class="language-php">public static function sign($dataStr, $privateKey)
{
    $dataStr = self::str2utf8($dataStr);
    $privateKeyId = openssl_get_privatekey($privateKey);
    openssl_sign($dataStr, $sign, $privateKeyId, self::SIGNATURE_ALGORITHM);
    openssl_free_key($privateKeyId);
    return base64_encode($sign);
}
</code></pre>
<h2 id="java-1">Java</h2>
<p><strong>RSAUtils.sign</strong></p>
<pre><code class="language-Java">static String sign(String data, String privateKey) throws Exception {
    byte[] keyBytes = Base64.decode(privateKey);
    PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);

    KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
    PrivateKey privateK   = keyFactory.generatePrivate(pkcs8KeySpec);
    Signature signature   = Signature.getInstance(SIGNATURE_ALGORITHM);

    signature.initSign(privateK);
    signature.update(data.getBytes(ENCODING));
    return Base64.encodeToString(signature.sign());
}
</code></pre>
<h1 id="验签">验签</h1>
<p>公钥验签。</p>
<h2 id="php-2">PHP</h2>
<p><strong>RSAUtils::verifySign</strong></p>
<pre><code class="language-php">public static function verifySign($dataStr, $publicKey, $sign)
{
    $dataStr   = self::str2utf8($dataStr);
    $publicKeyId = openssl_get_publickey($publicKey);
    return (boolean) openssl_verify($dataStr, base64_decode($sign), $publicKeyId, self::SIGNATURE_ALGORITHM);
}
</code></pre>
<h2 id="java-2">Java</h2>
<p><strong>RSAUtils.verifySign</strong></p>
<pre><code class="language-Java">static boolean verifySign(String data, String publicKey, String sign) throws Exception {
    try {
      byte[] keyBytes = Base64.decode(publicKey);

      X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
      KeyFactory keyFactory      = KeyFactory.getInstance(KEY_ALGORITHM);
      PublicKey publicK          = keyFactory.generatePublic(keySpec);
      Signature signature      = Signature.getInstance(SIGNATURE_ALGORITHM);

      signature.initVerify(publicK);
      signature.update(data.getBytes(ENCODING));

      return signature.verify(Base64.decode(sign));
    } catch (Exception e) {
      throw e;
    }
}
</code></pre>
<h1 id="加密">加密</h1>
<h2 id="公钥加密">公钥加密</h2>
<h3 id="php-3">PHP</h3>
<p><strong>RSAUtils::encryptByPublicKey</strong></p>
<pre><code class="language-php">public static function encryptByPublicKey($dataStr, $publicKey)
{
    $dataStr   = self::str2utf8($dataStr);
    $publicKeyId = openssl_get_publickey($publicKey);
    $data      = "";

    $dataArray = str_split($dataStr, self::PRIVATE_KEY_BITS / 8 - 11);
    foreach ($dataArray as $value) {
      openssl_public_encrypt($value,$encryptedTemp, $publicKeyId,self::EN_DE_ALGORITHM);
      $data .= $encryptedTemp;
    }
    openssl_free_key($publicKeyId);
    return base64_encode($data);
}
</code></pre>
<h3 id="java-3">Java</h3>
<p><strong>RSAUtils.encryptByPublicKey</strong></p>
<pre><code class="language-Java">static String encryptByPublicKey(String dataStr, String publicKey) throws Exception {
    byte[] data   = dataStr.getBytes(ENCODING);
    byte[] keyBytes = Base64.decode(publicKey);

    X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
    KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
    Key publicK         = keyFactory.generatePublic(x509KeySpec);
    Cipher cipher         = Cipher.getInstance(keyFactory.getAlgorithm());

    cipher.init(Cipher.ENCRYPT_MODE, publicK);
    int inputLen = data.length;
    ByteArrayOutputStream out = new ByteArrayOutputStream();

    int offSet = 0;
    byte[] cache;
    int i = 0;
    while (inputLen - offSet &gt; 0) {
      if (inputLen - offSet &gt; MAX_ENCRYPT_BLOCK) {
            cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
      } else {
            cache = cipher.doFinal(data, offSet, inputLen - offSet);
      }
      out.write(cache, 0, cache.length);
      i++;
      offSet = i * MAX_ENCRYPT_BLOCK;
    }
    byte[] encryptedData = out.toByteArray();
    out.close();
    return Base64.encodeToString(encryptedData);
}
</code></pre>
<h2 id="私钥加密">私钥加密</h2>
<h3 id="php-4">PHP</h3>
<p><strong>RSAUtils::encryptByPrivateKey</strong></p>
<pre><code class="language-php">public static function encryptByPrivateKey($dataStr, $privateKey)
{
    $dataStr      = self::str2utf8($dataStr);
    $privateKeyId = openssl_get_privatekey($privateKey);
    $data         = "";

    $dataArray = str_split($dataStr, self::PRIVATE_KEY_BITS / 8 - 11);
    foreach ($dataArray as $value) {
      openssl_private_encrypt($value,$encryptedTemp, $privateKeyId,self::EN_DE_ALGORITHM);
      $data .= $encryptedTemp;
    }
    openssl_free_key($privateKeyId);
    return base64_encode($data);
}
</code></pre>
<h3 id="java-4">Java</h3>
<p><strong>RSAUtils.encryptByPrivateKey</strong></p>
<pre><code class="language-Java">static String encryptByPrivateKey(String dataStr, String privateKey) throws Exception {
    byte[] data   = dataStr.getBytes(ENCODING);
    byte[] keyBytes = Base64.decode(privateKey);

    PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
    KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
    Key privateK          = keyFactory.generatePrivate(pkcs8KeySpec);
    Cipher cipher         = Cipher.getInstance(keyFactory.getAlgorithm());

    cipher.init(Cipher.ENCRYPT_MODE, privateK);
    int inputLen = data.length;
    ByteArrayOutputStream out = new ByteArrayOutputStream();

    int offSet = 0;
    byte[] cache;
    int i = 0;
    while (inputLen - offSet &gt; 0) {
      if (inputLen - offSet &gt; MAX_ENCRYPT_BLOCK) {
            cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
      } else {
            cache = cipher.doFinal(data, offSet, inputLen - offSet);
      }
      out.write(cache, 0, cache.length);
      i++;
      offSet = i * MAX_ENCRYPT_BLOCK;
    }
    byte[] encryptedData = out.toByteArray();
    out.close();
    return Base64.encodeToString(encryptedData);
}
</code></pre>
<h1 id="解密">解密</h1>
<h2 id="公钥解密">公钥解密</h2>
<h3 id="php-5">PHP</h3>
<p><strong>RSAUtils::decryptByPublicKey</strong></p>
<pre><code class="language-php">public static function decryptByPublicKey($encryptData, $publicKey) {
    $decrypted   = "";
    $decodeStr   = base64_decode($encryptData);
    $publicKeyId = openssl_get_publickey($publicKey);

    $enArray = str_split($decodeStr, self::PRIVATE_KEY_BITS / 8);

    foreach ($enArray as $value) {
      openssl_public_decrypt($value,$decryptedTemp, $publicKeyId,self::EN_DE_ALGORITHM);
      $decrypted .= $decryptedTemp;
    }
    openssl_free_key($publicKeyId);
    return $decrypted;
}
</code></pre>
<h3 id="java-5">Java</h3>
<p><strong>RSAUtils.decryptByPublicKey</strong></p>
<pre><code class="language-Java">static String decryptByPublicKey(String encryptedDataStr, String publicKey) throws Exception {
    byte[] encryptedData = Base64.decode(encryptedDataStr);
    byte[] keyBytes      = Base64.decode(publicKey);

    X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
    KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
    Key publicK = keyFactory.generatePublic(x509KeySpec);
    Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());

    cipher.init(Cipher.DECRYPT_MODE, publicK);
    int inputLen = encryptedData.length;
    ByteArrayOutputStream out = new ByteArrayOutputStream();

    int offSet = 0;
    byte[] cache;
    int i = 0;
    while (inputLen - offSet &gt; 0) {
      if (inputLen - offSet &gt; MAX_DECRYPT_BLOCK) {
            cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
      } else {
            cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
      }
      out.write(cache, 0, cache.length);
      i++;
      offSet = i * MAX_DECRYPT_BLOCK;
    }
    byte[] decryptedData = out.toByteArray();
    out.close();
    return new String(decryptedData, ENCODING);
}
</code></pre>
<h2 id="私钥解密">私钥解密</h2>
<h3 id="php-6">PHP</h3>
<p><strong>RSAUtils::decryptByPrivateKey</strong></p>
<pre><code class="language-php">public static function decryptByPrivateKey($encryptData, $private) {
    $decrypted    = "";
    $decodeStr    = base64_decode($encryptData);
    $privateKeyId = openssl_get_privatekey($private);

    $enArray = str_split($decodeStr, self::PRIVATE_KEY_BITS / 8);

    foreach ($enArray as $value) {
      openssl_private_decrypt($value,$decryptedTemp, $privateKeyId,self::EN_DE_ALGORITHM);
      $decrypted .= $decryptedTemp;
    }
    openssl_free_key($privateKeyId);
    return $decrypted;
}
</code></pre>
<h3 id="java-6">Java</h3>
<p><strong>RSAUtils.decryptByPrivateKey</strong></p>
<pre><code class="language-php">static String decryptByPrivateKey(String encryptedDataStr, String privateKey) throws Exception {
    byte[] encryptedData = Base64.decode(encryptedDataStr);
    byte[] keyBytes      = Base64.decode(privateKey);

    PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
    KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
    Key privateK          = keyFactory.generatePrivate(pkcs8KeySpec);
    Cipher cipher         = Cipher.getInstance(keyFactory.getAlgorithm());

    cipher.init(Cipher.DECRYPT_MODE, privateK);
    int inputLen = encryptedData.length;
    ByteArrayOutputStream out = new ByteArrayOutputStream();

    int offSet = 0;
    byte[] cache;
    int i = 0;
    while (inputLen - offSet &gt; 0) {
      if (inputLen - offSet &gt; MAX_DECRYPT_BLOCK) {
            cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
      } else {
            cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
      }
      out.write(cache, 0, cache.length);
      i++;
      offSet = i * MAX_DECRYPT_BLOCK;
    }
    byte[] decryptedData = out.toByteArray();
    out.close();
    return new String(decryptedData, ENCODING);
}
</code></pre>
<h1 id="demo">Demo</h1>
<p>完整 Demo 源码:BNDong/demo/PhpJavaRsa</p><br><br>
来源:https://www.cnblogs.com/bndong/p/11842135.html
頁: [1]
查看完整版本: Java & PHP RSA 互通密钥、签名、验签、加密、解密