java 和 php 在处理 RSA 加密的时候是有差别的,java 处理的 public/private key 文件在 php 里面是没有办法处理的,需要进行格式转换,而通过 openssl 直接生成的 public/private key 文件在 java 里面是不能直接实用的,所以如果双方互通就涉及到格式转换的问题。而往往因为不用业务之间需要这种语言上的加密转换,如果不知道这种差异,总是无法得到正确的结果。

一般通过两个函数就可以判断你的 key 格式是否是你可以处理的:

openssl_pkey_get_public
openssl_pkey_get_private

如果这两个函数返回的是 false ,则你的 key 格式就是 php 处理不了的。

举个例子:某平台的接口发给你了一个 public key ,你通过 public key 对数据进行加密传输到该平台,该平台通过 private key 对你传输的数据进行解密,而对方平台用的是 java 语言,刚好给你的 public key 格式也是 java 可以处理的,而你方的编程语言为 php ,此时就需要处理,代码如下:

class RsaCrypt {

/**
* encrypt with public key
* @param $data;
* @param $rsakeypath
*/
public static function encryptPublic($data, $rsakeypath) {
$content = self::getContent($rsakeypath);
if ($content) {
$pem = self::transJavaRsaKeyToPhpOpenSSL($content);
$pem = self::appendFlags($pem, true);
$res = openssl_pkey_get_public($pem);
if ($res) {
$opt = openssl_public_encrypt($data, $result, $res);
if ($opt) {
return $result;
}
}
}
return false;
}

/**
* decrypt with private key
* @param $data
* @param $rsakeypath
*/
public static function decryptPrivate($data, $rsakeypath) {
$content = self::getContent($rsakeypath);
if ($content) {
$pem = self::transJavaRsaKeyToPhpOpenSSL($content);
$pem = self::appendFlags($pem, false);
$res = openssl_pkey_get_private($pem);
if ($res) {
$opt = openssl_private_decrypt($data, $result, $res);
if ($opt) {
return $result;
}
}
}
return false;
}

/**
* get content forom file
* @param $filepath
* @return $content
*/
private static function getContent($filepath) {
if (is_file($filepath)) {
$content = file_get_contents($filepath);
return strtr($content, array(
"\r\n" => "",
"\r" => "",
"\n" => "",
));
}
return false;
}

/**
* trans java's rsa key format to php openssl can read
* @param $content
* @return string
*/
private static function transJavaRsaKeyToPhpOpenSSL($content) {
if ($content) {
return trim(chunk_split($content, 64, "\n"));
}
return false;
}

/**
* append Falgs to content
* @param $content
* @param $isPublic
* @return string
*/
private static function appendFlags($content, $isPublic = true) {
if ($isPublic) {
return "-----BEGIN PUBLIC KEY-----\n" . $content . "\n-----END PUBLIC KEY-----\n";
}
else {
return "-----BEGIN PRIVATE KEY-----\n" . $content . "\n-----END PRIVATE KEY-----\n";
}
}
}

上面这段代码主要完成了 public key 加密和 private key 解密两个方法。有时候我们还需要 public key 解密和 private key 加密,相关的函数在 openssl 的扩展模块都可以找到。

openssl_public_decrypt
openssl_public_encrypt
openssl_private_decrypt
openssl_private_encrypt