【发布时间】:2020-04-24 06:03:26
【问题描述】:
我正在与第三方合作,出于隐私考虑,我们要求在通过网络发送电子邮件地址之前对其进行加密。当我在命令行上使用 openssl 加密电子邮件地址时,一切正常。但是,我的 Java 8 实现会生成加密字符串,第三方无法使用他们的私钥解密。
私钥是按需从提供者那里检索的,因为它们会在某个时间间隔更改其公钥。以下是用于在本地创建公钥的公钥响应示例。
{"publicKey":"-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAh2+Bp9cU/8W2Qp6dUhH4\n7K079gL4IKc2ZnfnkKBZFEdmXUoaVsaEk/oMf/w/coOIbl36bcZVDJrp0okuPGNf\n5XRsIUbClrdPGr/pSEszS4pEZR5PvYMBRF3uile8OikiTAKQlTg+LZhdE2MCHPOv\nLZBAHH6wOj4nO/JsjbRXsNU+JyaDnc6RpFsw6zdcFiTDBSKRW0XukthnqffayWkk\nZ2HcpgJDEq8RbYV1Bb9rObvFmid/Rxj+YdhMqrDmhG5hmPSj/QXEKnuY988aPANa\nfnIRw0JnszOL0FOulVpBLGvQc6BcIaKWxSRUJFb3sM1RKMgJsFyRVLkEaMnCtwtW\ncve8Mhvs3luPM6dvggDUYwivu31Mk8sbAsB846JmpQH4SF2A7CpHo1teX7EgwwLJ\nitX6UfjIaU9Xx6BKFPcW+VgqrFYY5CCBxXD8toS5dbI14RQVUHz+3wFywtBRHO/Q\njk/u83wgdKDH38+TeBiYLUNqZ3DU5E5PU21eOtqTQ7T3g8L1bcq9zhrXGf0ONNOS\nEL0RCGvMgGm5nSMkV1maaYJpd1ArufrIDoSIiK+twpx7Rgkwxe7xPCT4LtJ+lQoC\nswDHd7kxVa4Toa2SqqT79S4+0Z52+Ke4tfRujEkPv5m6oCUwBcUhPGN7K6ie/E7X\nJN9kIq7QLV3ef+QUbzYiZZsCAwEAAQ==\n-----END PUBLIC KEY-----\n","encryptionKeyId":"ENCRYPTION-KEY-ID-2020-04-01T18:00:13.367Z"}
这是一个使用命令行加密字符串的示例:
首先从提供者处接收最新的公钥。
curl -s "http://stg.api.bazaarvoice.com/notifications/rsa_encryption_key/public/current/" | jq -r '.publicKey' > public_staging_key.pem
echo "testuser3@mailtest.nexus.bazaarvoice.com" | openssl rsautl -encrypt -pubin -inkey public_staging_key.pem | xxd -p | tr -d '\n' > encrypted_example_1.txt
这个加密的电子邮件地址可以被第三方使用他们的私钥正确解密。
下面是我的 java 实现,它生成的电子邮件地址不能被第三方使用他们的私钥解密。
@Bean
@Qualifier(value="keySettings")
public BazaarVoiceKeySettings keySettings() throws IOException {
final String uri = bazaarVoiceSettings.getPiePublicKeyUri();
RestTemplate restTemplate = new RestTemplate();
BazaarVoiceKeyResponse keyResponse = restTemplate.getForObject(uri, BazaarVoiceKeyResponse.class);
BazaarVoiceKeySettings keySettings = new BazaarVoiceKeySettings();
String pubKeyPEM = keyResponse.getPublicKey().replace("-----BEGIN PUBLIC KEY-----\n", "")
.replace("-----END PUBLIC KEY-----", "").replaceAll("\\s", "");
// create the key factory
try {
KeyFactory kFactory = KeyFactory.getInstance("RSA");
// decode base64 of your key
byte[] decodedBytes = Base64.getMimeDecoder().decode(pubKeyPEM);
// generate the public key
X509EncodedKeySpec spec = new X509EncodedKeySpec(decodedBytes);
RSAPublicKey rsaPublicKey = (RSAPublicKey) kFactory.generatePublic(spec);
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-512ANDMGF1PADDING");
cipher.init(Cipher.ENCRYPT_MODE, rsaPublicKey);
keySettings.setCipher(cipher);
keySettings.setEncryptionKeyId(keyResponse.getEncryptionKeyId());
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
}
return keySettings;
}
private String encryptEmail(String emailAddress) throws BadPaddingException, IllegalBlockSizeException {
Cipher cipher = keySettings.getCipher();
byte[] cipherText = cipher.doFinal(emailAddress.getBytes(Charsets.UTF_8));
String encryptedString = DatatypeConverter.printHexBinary(cipherText);
return encryptedString;
}
【问题讨论】:
-
我还没有看过你的代码或任何东西——只是为了你的信息——这个第三方提供商使用的安全性完全是废话,他们不知道自己在做什么。他们通过 unsecured HTTP 向您发送他们的公钥,然后希望您跳过箍来加密电子邮件地址,而他们可以只使用 HTTPS 并消除所有这些废话......并且拥有它实际上也很安全!
-
您的
openssl rsautl未使用 OAEP;默认情况下,它使用 PKCS1v1.5 类型 2 即 RSAES-PKCS1-v1_5 进行加密,对于歇斯底里的葡萄干,openssl只需调用-pkcs。对于类似的葡萄干,Java 将其称为RSA/ECB/PKCS1Padding(不区分大小写)。此外,您的openssl版本在加密值中包含换行符,这对服务器可能或可能无关紧要。 @Luke:加上 PCI 不关心电子邮件。 GDPR 等其他事情可以做,但 PCI 不做。
标签: java encryption cryptography rsa