使用java加密库和RSA 4096公钥的加密无法正常工作

使用java加密库和RSA 4096公钥的加密无法正常工作,java,encryption,cryptography,rsa,Java,Encryption,Cryptography,Rsa,我与第三方合作,出于隐私考虑,我们要求在通过网络发送电子邮件地址之前对其进行加密。当我在命令行上使用openssl加密电子邮件地址时,一切正常。但是,我的Java 8实现生成的加密字符串不能由第三方使用其私钥解密 @Bean @Qualifier(value="keySettings") public BazaarVoiceKeySettings keySettings() throws IOException { final String uri = baza

我与第三方合作,出于隐私考虑,我们要求在通过网络发送电子邮件地址之前对其进行加密。当我在命令行上使用openssl加密电子邮件地址时,一切正常。但是,我的Java 8实现生成的加密字符串不能由第三方使用其私钥解密

@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;
    }
私钥是按需从提供者检索的,因为提供者每隔一段时间更改其公钥。下面是一个用于在本地创建公钥的公钥响应示例

{"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
此加密电子邮件地址可以由第三方使用其私钥正确解密

@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;
    }
下面是我的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;
    }

正如@dave_thompson_085所回答的,解决方案是将我的编码模式更改为RSA/ECB/PKCS1Padding

正如@dave_thompson_085所回答的,解决方案是将我的编码模式更改为RSA/ECB/PKCS1Padding

我还没有查看您的代码或任何东西-但仅供参考-此第三方提供商使用的安全性完全是垃圾,他们不知道自己在做什么。他们通过不安全的HTTP向你发送他们的公钥,然后希望你跳过圈套对电子邮件地址进行加密,而他们只需要使用HTTPS就可以消除所有这些垃圾。。。并且让它实际上也是安全的!您的
openssl rsautl
未使用OAEP;默认情况下,加密使用PKCS1v1.5 type 2又名RSAES-PKCS1-v1_5,它
openssl
用于歇斯底里的葡萄干调用,只需
-pkcs
。对于类似的理由,Java调用它
RSA/ECB/PKCS1Padding
(不区分大小写)。另外,您的
openssl
版本在加密的值中包含一个换行符,这可能对服务器有影响,也可能对服务器没有影响@卢克:而且PCI不关心电子邮件。其他的事情,比如GDPR,但不是PCI。我还没有看过你的代码或任何东西-只是为了你的信息-这个第三方提供商使用的安全性是完全垃圾,他们不知道他们在做什么。他们通过不安全的HTTP向你发送他们的公钥,然后希望你跳过圈套对电子邮件地址进行加密,而他们只需要使用HTTPS就可以消除所有这些垃圾。。。并且让它实际上也是安全的!您的
openssl rsautl
未使用OAEP;默认情况下,加密使用PKCS1v1.5 type 2又名RSAES-PKCS1-v1_5,它
openssl
用于歇斯底里的葡萄干调用,只需
-pkcs
。对于类似的理由,Java调用它
RSA/ECB/PKCS1Padding
(不区分大小写)。另外,您的
openssl
版本在加密的值中包含一个换行符,这可能对服务器有影响,也可能对服务器没有影响@卢克:而且PCI不关心电子邮件。其他事情,比如GDPR,但不是PCI。