我目前担心RSA密钥管理问题。具体来说,我想在Java中创建RSA密钥对,签署一些内容(即字符串)将公钥,签名和签名的String导出到JSON文件中(是的,JSON!),将其导入另一个使用PHP的服务器,并验证签名,这意味着我必须从JSON数据重新创建一个可用的密钥。
另外,我必须采用相反的方式(在PHP中创建,在Java中验证)
另外,我需要将私钥导出为JSON(是的,JSON再次:)!并导出它。
所以在Java方面,一切似乎都很顺利。我可以创建密钥,将它们导出为JSON,重新导入它们并使用它们。创建和验证签名没有问题。这是代码:
创建密钥对:
public static final String ALGORITHM = "RSA";
public static final int KEYSIZE = 4096;
public static KeyPair createKeyPair() throws NoSuchAlgorithmException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM);
keyPairGenerator.initialize(KEYSIZE);
return keyPairGenerator.genKeyPair();
}
将密钥导出到String(最终将在JSON对象中) - 私钥的代码类似:
public static final String PUBLICKEY_PREFIX = "-----BEGIN PUBLIC KEY-----";
public static final String PUBLICKEY_POSTFIX = "-----END PUBLIC KEY-----";
public static String exportPublicKey(Key key) {
return PUBLICKEY_PREFIX + DatatypeConverter.printBase64Binary(key.getEncoded()) + PUBLICKEY_POSTFIX;
}
上述结果将是例如
"-----BEGIN PUBLIC KEY-----MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtBPxEtEWws2pPN5HCB795+nQyX23ZTKJt5PoMQQpwjOY/7U5ODkwHpuHWUhAuB1qTKTUdEWbe5x7WkD6/ksSib64Xq3jIeLQrfhj+g3bGsQjtca5LyIZ/J+G55l7k/Ny/lfQQNfquCcILHW7DrnzTb0D56IOBsR/r0Vv8ZvUxnaXUQtif8Q6dme8uoqzfnF46McqThnvPDxdHmhumb7tqPffzt35bRxFBvMcAWqW0FcPAeXD6cmsOBAATh/gVe1g5J89FyK8PhkNjW3uLMmknCTQg9KoWh4+DDRrLXxqSCBbaIRMCtbhShZOIbtjurJ+ZjhR/WSPnzJrl84rTjWG3Po6jsdtJ0pRHP4YnXXXJWhMt2oTOtHTQj4+99UX7Yuyp2tmFaEdQXvm3k/qbT9PBlwEovC2yqbFMcrM7sAW09NiSDdm1ipzV+vsOGuRXF2vtNX6pplifp5va5hQY/UqmlHSygvecImP5ennFOP7G62W/Q0w0qRzOXmFHN6Hsi8D1ZlWwgjyNahoX2yvgBMzy7MMYJcqiS9GOOETaenXTZViiipceGk96crjh6LG7RudMb+WN2yRXnjdWYd0GYPsaXz/faMohfXRXzRq/oIGZ4EdHhp9TknL2rCZmfR3N4Ozi1BkszAmmQeeNrUgxEjB8TdSer4p4DfR22NFcs9M3YkCAwEAAQ==-----END PUBLIC KEY-----"
然后,我再次从JSON中读取了键:
public static PublicKey importPublicKey(String key) throws InvalidKeySpecException, NoSuchAlgorithmException {
key = stripKey(key);
byte[] keyBytes = DatatypeConverter.parseBase64Binary(key);
return KeyFactory.getInstance(ALGORITHM).generatePublic(new X509EncodedKeySpec(keyBytes));
}
public static PrivateKey importPrivateKey(String key) throws InvalidKeySpecException, NoSuchAlgorithmException {
key = stripKey(key);
byte[] keyBytes = DatatypeConverter.parseBase64Binary(key);
return KeyFactory.getInstance(ALGORITHM).generatePrivate(new PKCS8EncodedKeySpec(keyBytes));
}
这对我来说很好。我可以创建,存储,重新导入和使用密钥 - 包括公钥和私钥。我使用
创建的签名public static String createSignature(PrivateKey privateKey, String message) {
String algorithm = "SHA512withRSA";
Signature signature = null;
String signedString = null;
try {
signature = Signature.getInstance(algorithm);
signature.initSign(privateKey);
signature.update(message.getBytes());
byte[] signatureByteArray = signature.sign();
signedString = "-----BEGIN SIGNATURE-----"
+ DatatypeConverter.printBase64Binary(signatureByteArray)
+ "-----END SIGNATURE-----";
} catch(Exception e) {
e.printStackTrace();
}
return signedString;
}
可以使用java.security.Signature.verify()
轻松验证。到目前为止,我很高兴。
现在棘手的部分:我将创建的JSON发送到另一台服务器,在这里,我的麻烦开始了:
首先,我从字符串中删除标题和尾部(“----- BEGIN”等等......),然后,我使用base64_decode()
和ASSUME,结果可以使用作为调用openssl_pkey_get_private()
无论如何,我得到像
这样的错误openssl_sign(): supplied key param cannot be coerced into a private key
每次我尝试使用我的钥匙。
所以在Java中,我创建了一个new X509EncodedKeySpec(keyBytes)
,然而,在PHP中,没有这样的功能(?)
我的en / decode在哪里出错了?我实际上有点失落:(
答案 0 :(得分:1)
您的密钥目前以二进制格式存储,通常称为“DER”格式。这就是Java存储密钥的方式。为了能够从PHP读取它,您必须将密钥转换为PEM格式,这是OpenSSL的格式。因此,PHP要求密钥为PEM格式。这是一个PHP函数,它可以将DER编码的密钥转换为PHP中的PEM编码密钥:
function X509_to_pem($der_data) {
$BEGIN= "-----BEGIN SIGNATURE-----";
$END = "-----BEGIN SIGNATURE-----";
$base64Encoded= base64_encode($der_data);
$pem = $BEGIN . "\n";
$pem .= chunk_split($base64Encoded, 64, "\n");
$pem .= $END . "\n";
return $pem;
}
答案 1 :(得分:1)
public class KeyTest{
static final String ALGORITHM = "RSA";
static final int KEYSIZE = 1024;
static final String SIGNATURE_ALGORITHM = "SHA512withRSA";
static final String PUBLICKEY_PREFIX = "-----BEGIN PUBLIC KEY-----";
static final String PUBLICKEY_POSTFIX = "-----END PUBLIC KEY-----";
static final String PRIVATEKEY_PREFIX = "-----BEGIN RSA PRIVATE KEY-----";
static final String PRIVATEKEY_POSTFIX = "-----END RSA PRIVATE KEY-----";
public static void main(String args[]) {
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM);
keyPairGenerator.initialize(KEYSIZE);
KeyPair keyPair = keyPairGenerator.genKeyPair();
// THIS IS java.security
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
System.out.println("Public java.security: Algorithm: " + publicKey.getAlgorithm() + "Format: " + publicKey.getFormat());
System.out.println("Private java.security: Algorithm: " + privateKey.getAlgorithm() + "Format: " + privateKey.getFormat() + "\n");
// THIS IS DER:
byte[] publicKeyDER = publicKey.getEncoded();
byte[] privateKeyDER = privateKey.getEncoded();
System.out.println("Public DER: "+Arrays.toString(publicKeyDER));
System.out.println("Private DER: "+Arrays.toString(privateKeyDER) + "\n");
// THIS IS PEM:
String publicKeyPEM = PUBLICKEY_PREFIX + "\n" + DatatypeConverter.printBase64Binary(publicKey.getEncoded()).replaceAll("(.{64})", "$1\n") + "\n" + PUBLICKEY_POSTFIX;
String privateKeyPEM = PRIVATEKEY_PREFIX + "\n" + DatatypeConverter.printBase64Binary(privateKey.getEncoded()).replaceAll("(.{64})", "$1\n") + "\n" + PRIVATEKEY_POSTFIX;
System.out.println("Public PEM: " + "\n"+publicKeyPEM);
System.out.println("Private PEM: " + "\n"+privateKeyPEM + "\n");
// Signing the teststring
String message = "Lorem ipsum dolor sit amet";
Signature sig = Signature.getInstance(SIGNATURE_ALGORITHM);
sig.initSign(privateKey);
sig.update(message.getBytes());
byte[] signatureByteArray = sig.sign();
String signature = "-----BEGIN SIGNATURE-----" + "\n"
+ DatatypeConverter.printBase64Binary(signatureByteArray).replaceAll("(.{64})", "$1\n") + "\n"
+ "-----END SIGNATURE-----";
System.out.println("Message Plaintext: " + message);
System.out.println("Signature: " + "\n" + signature + "\n");
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
}
这样的输出是这样的:
Public java.security: Algorithm: RSAFormat: X.509
Private java.security: Algorithm: RSAFormat: PKCS#8
Public DER: [48, -127, -97, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 1, 5, 0, 3, -127, -115, 0, 48, -127, -119, 2, -127, -127, 0, -125, -8, 66, -86, -27, -55, 14, 50, 26, -103, -87, 102, 47, 126, -70, 57, -27, 103, -95, 10, 26, 25, -3, -18, -44, -85, 11, -19, -92, 111, 22, -6, 94, 79, -126, 32, -68, -82, -67, 24, -108, 9, 46, -100, 25, -37, 56, 2, -122, -31, -93, 56, -39, 79, -67, 33, -126, -13, -72, -120, 115, 3, -57, -120, -86, 119, 57, -110, -6, -11, -36, 109, -113, -69, -11, -81, -94, 47, 59, -7, 119, 108, -89, -26, -55, 117, -74, 125, -39, -1, 116, -116, -9, -60, -57, -78, -118, 45, 38, 120, -43, 123, -51, -104, 42, -47, 101, -120, 78, 9, -2, -84, 113, -42, -71, 101, 3, -44, -58, 39, 50, 96, 83, 90, 71, 41, 83, -13, 2, 3, 1, 0, 1]
Private DER: [48, -126, 2, 118, 2, 1, 0, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 1, 5, 0, 4, -126, 2, 96, 48, -126, 2, 92, 2, 1, 0, 2, -127, -127, 0, -125, -8, 66, -86, -27, -55, 14, 50, 26, -103, -87, 102, 47, 126, -70, 57, -27, 103, -95, 10, 26, 25, -3, -18, -44, -85, 11, -19, -92, 111, 22, -6, 94, 79, -126, 32, -68, -82, -67, 24, -108, 9, 46, -100, 25, -37, 56, 2, -122, -31, -93, 56, -39, 79, -67, 33, -126, -13, -72, -120, 115, 3, -57, -120, -86, 119, 57, -110, -6, -11, -36, 109, -113, -69, -11, -81, -94, 47, 59, -7, 119, 108, -89, -26, -55, 117, -74, 125, -39, -1, 116, -116, -9, -60, -57, -78, -118, 45, 38, 120, -43, 123, -51, -104, 42, -47, 101, -120, 78, 9, -2, -84, 113, -42, -71, 101, 3, -44, -58, 39, 50, 96, 83, 90, 71, 41, 83, -13, 2, 3, 1, 0, 1, 2, -127, -128, 39, -40, 45, -16, -63, 62, 9, -18, 48, -65, -46, 56, -117, 0, 125, 35, 123, -46, -28, -7, 82, -42, 36, 40, 22, -57, -87, -21, 79, 41, 71, 75, -62, 107, -55, 3, 47, 84, -90, -67, 35, -4, -3, -72, -99, -55, -27, 72, 70, 7, 28, 43, -50, -40, -41, 102, -91, -50, 6, 26, 20, 119, -64, -89, 96, 97, -101, 103, -46, 34, 95, -91, 19, 43, 4, 63, -121, 30, 85, 11, 86, 33, 58, -62, -108, 74, 56, 81, -123, 24, -8, 121, -11, -119, 43, -97, -50, 24, -60, 72, -15, 6, -87, 123, -16, 123, -17, -39, 56, -44, 97, -57, -8, 16, 9, -72, 68, 53, 1, 87, 94, -16, -54, 115, 15, -34, 93, -23, 2, 65, 0, -59, 121, -7, -34, 118, -24, 27, -9, 83, -125, -115, 120, -78, 33, -122, -78, 7, 33, 18, -44, -57, -87, 50, 99, -105, -68, -69, -82, 116, 53, -119, 113, 41, -115, 83, 66, -55, -9, -47, -12, 49, -58, 14, 68, -76, 106, 95, 102, -96, 90, -61, -40, -17, -10, 81, 116, -6, -125, -68, -33, -18, -19, 43, -11, 2, 65, 0, -85, 20, 118, 69, 108, -51, 79, -63, 70, -35, -16, -47, 81, -48, 51, 36, 99, 79, -78, -84, -86, 41, 49, -56, 101, 100, -80, 121, 53, -5, -98, -9, 53, 110, 58, -60, -39, 39, 100, -64, -108, 36, -29, -127, -13, -110, 120, 46, -31, -79, -10, -36, -26, -94, -117, -6, -76, 121, -15, -17, -31, 94, -73, 71, 2, 64, 119, 0, 35, 48, 9, 77, -92, 20, -83, -47, -9, -67, -60, -14, 105, 29, -3, 39, -44, 22, 63, 95, 89, -117, 36, -108, 74, 49, 61, -68, 73, 95, -43, 31, 98, 14, 60, 113, 71, -89, 53, 27, 89, -37, -45, 48, -54, -34, -88, 65, 42, 6, 31, -52, -70, -105, -104, -93, 44, 125, 113, -104, -96, -59, 2, 64, 122, -26, 48, 48, -97, -128, -66, -110, -78, 62, 46, 9, -79, 36, 72, 25, 19, -34, -27, 20, 117, 9, 50, -30, 43, 52, -78, 49, -31, 61, -23, 108, -35, -51, 90, 26, -97, -123, 85, 51, -93, 56, -4, -41, 22, 11, 90, -101, 19, 55, -83, -121, -13, -121, 65, -41, -48, 94, -22, 22, -47, 104, 33, 113, 2, 65, 0, -65, 101, -127, -118, 21, 122, -114, 47, 65, -96, -37, -104, 100, 52, 38, -81, 9, -9, 120, -56, -36, -92, -52, 7, -47, -8, -101, 83, -24, -82, -81, -60, 71, -47, 111, -49, 1, 46, 16, -52, -87, -79, 21, -68, 22, 18, -37, -62, 33, 102, 40, -49, -122, -98, -83, 1, 94, 29, -85, 93, -16, -7, -57, 119]
Public PEM:
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCD+EKq5ckOMhqZqWYvfro55Weh
ChoZ/e7UqwvtpG8W+l5PgiC8rr0YlAkunBnbOAKG4aM42U+9IYLzuIhzA8eIqnc5
kvr13G2Pu/Wvoi87+Xdsp+bJdbZ92f90jPfEx7KKLSZ41XvNmCrRZYhOCf6scda5
ZQPUxicyYFNaRylT8wIDAQAB
-----END PUBLIC KEY-----
Private PEM:
-----BEGIN RSA PRIVATE KEY-----
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIP4QqrlyQ4yGpmp
Zi9+ujnlZ6EKGhn97tSrC+2kbxb6Xk+CILyuvRiUCS6cGds4AobhozjZT70hgvO4
iHMDx4iqdzmS+vXcbY+79a+iLzv5d2yn5sl1tn3Z/3SM98THsootJnjVe82YKtFl
iE4J/qxx1rllA9TGJzJgU1pHKVPzAgMBAAECgYAn2C3wwT4J7jC/0jiLAH0je9Lk
+VLWJCgWx6nrTylHS8JryQMvVKa9I/z9uJ3J5UhGBxwrztjXZqXOBhoUd8CnYGGb
Z9IiX6UTKwQ/hx5VC1YhOsKUSjhRhRj4efWJK5/OGMRI8Qape/B779k41GHH+BAJ
uEQ1AVde8MpzD95d6QJBAMV5+d526Bv3U4ONeLIhhrIHIRLUx6kyY5e8u650NYlx
KY1TQsn30fQxxg5EtGpfZqBaw9jv9lF0+oO83+7tK/UCQQCrFHZFbM1PwUbd8NFR
0DMkY0+yrKopMchlZLB5Nfue9zVuOsTZJ2TAlCTjgfOSeC7hsfbc5qKL+rR58e/h
XrdHAkB3ACMwCU2kFK3R973E8mkd/SfUFj9fWYsklEoxPbxJX9UfYg48cUenNRtZ
29Mwyt6oQSoGH8y6l5ijLH1xmKDFAkB65jAwn4C+krI+LgmxJEgZE97lFHUJMuIr
NLIx4T3pbN3NWhqfhVUzozj81xYLWpsTN62H84dB19Be6hbRaCFxAkEAv2WBihV6
ji9BoNuYZDQmrwn3eMjcpMwH0fibU+iur8RH0W/PAS4QzKmxFbwWEtvCIWYoz4ae
rQFeHatd8PnHdw==
-----END RSA PRIVATE KEY-----
Message Plaintext: Lorem ipsum dolor sit amet
Signature:
-----BEGIN SIGNATURE-----
UxhWlr8Ks3PkfaKK8IGGolUs8qjvbE4dXs8ANUtJdw48g8nk6pOEuEscpSiszc1O
fBFEG6lexRFeW4+zpyWHN8oJpVaxz7sd2lstFqu/dUkU8HtPujKkwK6c/3pzsAt8
yHru/BPRwI8Wryqm2dfiHO4cXKq5rIXfj0sSXbwI1PE=
-----END SIGNATURE-----
现在我在PHP中对这些值进行了硬编码:
<?php
$publicKeyPEM = "-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCD+EKq5ckOMhqZqWYvfro55Weh
ChoZ/e7UqwvtpG8W+l5PgiC8rr0YlAkunBnbOAKG4aM42U+9IYLzuIhzA8eIqnc5
kvr13G2Pu/Wvoi87+Xdsp+bJdbZ92f90jPfEx7KKLSZ41XvNmCrRZYhOCf6scda5
ZQPUxicyYFNaRylT8wIDAQAB
-----END PUBLIC KEY-----";
$privateKeyPEM = "-----BEGIN RSA PRIVATE KEY-----
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIP4QqrlyQ4yGpmp
Zi9+ujnlZ6EKGhn97tSrC+2kbxb6Xk+CILyuvRiUCS6cGds4AobhozjZT70hgvO4
iHMDx4iqdzmS+vXcbY+79a+iLzv5d2yn5sl1tn3Z/3SM98THsootJnjVe82YKtFl
iE4J/qxx1rllA9TGJzJgU1pHKVPzAgMBAAECgYAn2C3wwT4J7jC/0jiLAH0je9Lk
+VLWJCgWx6nrTylHS8JryQMvVKa9I/z9uJ3J5UhGBxwrztjXZqXOBhoUd8CnYGGb
Z9IiX6UTKwQ/hx5VC1YhOsKUSjhRhRj4efWJK5/OGMRI8Qape/B779k41GHH+BAJ
uEQ1AVde8MpzD95d6QJBAMV5+d526Bv3U4ONeLIhhrIHIRLUx6kyY5e8u650NYlx
KY1TQsn30fQxxg5EtGpfZqBaw9jv9lF0+oO83+7tK/UCQQCrFHZFbM1PwUbd8NFR
0DMkY0+yrKopMchlZLB5Nfue9zVuOsTZJ2TAlCTjgfOSeC7hsfbc5qKL+rR58e/h
XrdHAkB3ACMwCU2kFK3R973E8mkd/SfUFj9fWYsklEoxPbxJX9UfYg48cUenNRtZ
29Mwyt6oQSoGH8y6l5ijLH1xmKDFAkB65jAwn4C+krI+LgmxJEgZE97lFHUJMuIr
NLIx4T3pbN3NWhqfhVUzozj81xYLWpsTN62H84dB19Be6hbRaCFxAkEAv2WBihV6
ji9BoNuYZDQmrwn3eMjcpMwH0fibU+iur8RH0W/PAS4QzKmxFbwWEtvCIWYoz4ae
rQFeHatd8PnHdw==
-----END RSA PRIVATE KEY-----";
$message_plaintext = "Lorem ipsum dolor sit amet";
$signature = "-----BEGIN SIGNATURE-----
UxhWlr8Ks3PkfaKK8IGGolUs8qjvbE4dXs8ANUtJdw48g8nk6pOEuEscpSiszc1O
fBFEG6lexRFeW4+zpyWHN8oJpVaxz7sd2lstFqu/dUkU8HtPujKkwK6c/3pzsAt8
yHru/BPRwI8Wryqm2dfiHO4cXKq5rIXfj0sSXbwI1PE=
-----END SIGNATURE-----";
function verify_signature($message, $public_key, $signature) {
$algorithm = OPENSSL_ALGO_SHA512;
$hash_algorithm = 'sha512';
$signature = str_replace('-----BEGIN SIGNATURE-----', '', $signature);
$signature = str_replace('-----END SIGNATURE-----', '', $signature);
$signature = base64_decode($signature);
$success = openssl_verify($message, $signature, $public_key, $algorithm);
return $success;
}
var_dump(verify_signature($message_plaintext, $publicKeyPEM, $signature));
?>
......这实际上有效。我仍然不明白为什么杰克的解决方案不起作用,但是哦,好吧......
希望这有助于其他人管理密钥,因为我没有在网上找到太多的跨平台示例......