【问题标题】:Java and OPENSSLJava 和 OPENSSL
【发布时间】:2020-11-23 16:26:45
【问题描述】:

我需要帮助来使用 openssl 解密加密文本的 base64 字符串。

在linux命令行中,我做了以下操作:

  1. 已生成公钥/私钥:
openssl genrsa -out private_key.pem 1024
openssl rsa -in private_key.pem -out public_key.pem -outform PEM -pubout

我的 private_key.pem 看起来像:

-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQDDu/0Fcq5/4M2t9Y+R4QvoDADQ+VaGSR3VEQiCV9xXcpkKAda+
nO2PrljIMcUO76O5a4twxxl1YT1dzKmj7T8i+EqYF1Y/1TxxWjIdo8hELD2Wug4d
ey3pMjI+5MXVraMyl5zEgfB64eTiu48LWygKi57Cfg41wKekSn2S/SvETQIDAQAB
AoGAFPgVwjioAyElR8av69PtP53RlJGxuE8q+AGMJNKe02t+g7jwtZkARk1KS6Ax
WUlJA/tGg/2Ad7fEKEFdxycKhVeF0ephOo8Xje6pMDDPpYSj/RlevUb60NEZZma1
PbA9TqS5Ys533jLYRbJUeNpufi0qQbRyB0QBJOUwbBHWDoECQQDsTYCoolsBHutY
YPZYBszOZhtxiDYqJ+B6/GoW/Y9h4HVg7CkKxaMdQBHbjTm+2YOH4SNHnwl7MVk3
cagbC/RhAkEA1AzKatUc7pUnkAO7VPM5luLnV/0ltpp6eveSgwxVs618a2BfFvS1
d8PAoKFCuCawTVd/GbY/fFKQab3hGiAXbQJBAOvIlZUukyG2KVzBO20wM9HK/p01
Ld64dXwiOvV/wj8GifjRDE7MT+rS0D7DVxhAz8aYdex0GzDKV9xD01pRfmECQBwi
9ljmnkgqEm3RkPHctC+JPBk4xeBM7yOR5ibtZBHLW08EIpnxLoMNvmmR/EBjIdGh
YoQO4q2kZvUg9NV6nKECQCFHa7lwlstxDqLgTzKHnRIK2hbUufrWKp+nDb18aqmF
eHvC4MZkixR+rykGRHsYjmwGKnXpbchKjC2iPFn1XY0=
-----END RSA PRIVATE KEY-----

我的公钥看起来像:

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDu/0Fcq5/4M2t9Y+R4QvoDADQ
+VaGSR3VEQiCV9xXcpkKAda+nO2PrljIMcUO76O5a4twxxl1YT1dzKmj7T8i+EqY
F1Y/1TxxWjIdo8hELD2Wug4dey3pMjI+5MXVraMyl5zEgfB64eTiu48LWygKi57C
fg41wKekSn2S/SvETQIDAQAB
-----END PUBLIC KEY-----
  1. 我可以使用我的 public_key.pem 创建一个 base64 字符串:
echo "Hola Mundo" | openssl rsautl -encrypt -pubin -inkey public_key.pem | base64 -w 0
gQO7XwvkClncfTpsv0jZ1Ptm2tI7YppHWdqwdrH2sZrG3ah5pcWt+PJ1q2ADPhZo8EURVmiYLO+q/P475/eUKY0h/T+IWQmV4lFCoXZfBzD3TzkN3nSmvj9HiR4psevYUa9HeOpECCXLJ1z8K4ut978zHtYKDi89k3VIdZUT6uY=
  1. 我可以使用我的 private_key.pem 解密字符串:
echo "gQO7XwvkClncfTpsv0jZ1Ptm2tI7YppHWdqwdrH2sZrG3ah5pcWt+PJ1q2ADPhZo8EURVmiYLO+q/P475/eUKY0h/T+IWQmV4lFCoXZfBzD3TzkN3nSmvj9HiR4psevYUa9HeOpECCXLJ1z8K4ut978zHtYKDi89k3VIdZUT6uY=" | base64 -d | openssl rsautl -decrypt -inkey private_key.pem

Hola Mundo

现在,我的问题是,在 JAVA 中,像这样加载私钥:

String key = "MIICXAIBAAKBgQDDu/0Fcq5/4M2t9Y+R4QvoDADQ+VaGSR3VEQiCV9xXcpkKAda+\n" +
        "nO2PrljIMcUO76O5a4twxxl1YT1dzKmj7T8i+EqYF1Y/1TxxWjIdo8hELD2Wug4d\n" +
        "ey3pMjI+5MXVraMyl5zEgfB64eTiu48LWygKi57Cfg41wKekSn2S/SvETQIDAQAB\n" +
        "AoGAFPgVwjioAyElR8av69PtP53RlJGxuE8q+AGMJNKe02t+g7jwtZkARk1KS6Ax\n" +
        "WUlJA/tGg/2Ad7fEKEFdxycKhVeF0ephOo8Xje6pMDDPpYSj/RlevUb60NEZZma1\n" +
        "PbA9TqS5Ys533jLYRbJUeNpufi0qQbRyB0QBJOUwbBHWDoECQQDsTYCoolsBHutY\n" +
        "YPZYBszOZhtxiDYqJ+B6/GoW/Y9h4HVg7CkKxaMdQBHbjTm+2YOH4SNHnwl7MVk3\n" +
        "cagbC/RhAkEA1AzKatUc7pUnkAO7VPM5luLnV/0ltpp6eveSgwxVs618a2BfFvS1\n" +
        "d8PAoKFCuCawTVd/GbY/fFKQab3hGiAXbQJBAOvIlZUukyG2KVzBO20wM9HK/p01\n" +
        "Ld64dXwiOvV/wj8GifjRDE7MT+rS0D7DVxhAz8aYdex0GzDKV9xD01pRfmECQBwi\n" +
        "9ljmnkgqEm3RkPHctC+JPBk4xeBM7yOR5ibtZBHLW08EIpnxLoMNvmmR/EBjIdGh\n" +
        "YoQO4q2kZvUg9NV6nKECQCFHa7lwlstxDqLgTzKHnRIK2hbUufrWKp+nDb18aqmF\n" +
        "eHvC4MZkixR+rykGRHsYjmwGKnXpbchKjC2iPFn1XY0=";

和这样加载的加密字符串:

String data = "I3E5pjXE0chhtmkFBa56PGtWv5XDcIXfi2h5e3Bi44CCMvaIQ7UT7XBwkGZTRR11wfQIl7MswcEebXDmmw/C6JobrqQHQ0rU7zLPOU8j24JCFiccxclq5efMAcIO/ZcSO34uObrFQwQ4L2ex/3xL7b/YKujCQDTtzQkxE2N1JPU=";

我怎样才能找回原来的“Hola Mundo”字符串?你能指出我正确的方向吗?

提前谢谢你。

【问题讨论】:

    标签: java openssl cryptography


    【解决方案1】:

    您正在努力解决的问题是私钥的格式/编码。

    您使用 OpenSSL 生成了 RSA 密钥对,并收到了一个采用“旧”PKCS1 编码的私钥,在 pem 字符串的开头可以清楚地看到:

    -----BEGIN RSA PRIVATE KEY-----
    

    不幸的是,Java 不能“开箱即用”地使用这种编码(您可以使用例如 Bouncy Castle 来读取这种键)。但是有一个解决方案,就是将密钥转换为(支持 Java 的)PKCS8 编码。只需使用

    转换密钥
    openssl pkcs8 -topk8 -nocrypt -in rsaprivatekeypkcs1.pem -out rsaprivatekeypkcs8.pem
    

    您将收到此私钥:

    -----BEGIN PRIVATE KEY-----
    MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMO7/QVyrn/gza31
    j5HhC+gMAND5VoZJHdURCIJX3FdymQoB1r6c7Y+uWMgxxQ7vo7lri3DHGXVhPV3M
    qaPtPyL4SpgXVj/VPHFaMh2jyEQsPZa6Dh17LekyMj7kxdWtozKXnMSB8Hrh5OK7
    jwtbKAqLnsJ+DjXAp6RKfZL9K8RNAgMBAAECgYAU+BXCOKgDISVHxq/r0+0/ndGU
    kbG4Tyr4AYwk0p7Ta36DuPC1mQBGTUpLoDFZSUkD+0aD/YB3t8QoQV3HJwqFV4XR
    6mE6jxeN7qkwMM+lhKP9GV69RvrQ0RlmZrU9sD1OpLliznfeMthFslR42m5+LSpB
    tHIHRAEk5TBsEdYOgQJBAOxNgKiiWwEe61hg9lgGzM5mG3GINion4Hr8ahb9j2Hg
    dWDsKQrFox1AEduNOb7Zg4fhI0efCXsxWTdxqBsL9GECQQDUDMpq1RzulSeQA7tU
    8zmW4udX/SW2mnp695KDDFWzrXxrYF8W9LV3w8CgoUK4JrBNV38Ztj98UpBpveEa
    IBdtAkEA68iVlS6TIbYpXME7bTAz0cr+nTUt3rh1fCI69X/CPwaJ+NEMTsxP6tLQ
    PsNXGEDPxph17HQbMMpX3EPTWlF+YQJAHCL2WOaeSCoSbdGQ8dy0L4k8GTjF4Ezv
    I5HmJu1kEctbTwQimfEugw2+aZH8QGMh0aFihA7iraRm9SD01XqcoQJAIUdruXCW
    y3EOouBPMoedEgraFtS5+tYqn6cNvXxqqYV4e8LgxmSLFH6vKQZEexiObAYqdelt
    yEqMLaI8WfVdjQ==
    -----END PRIVATE KEY-----
    

    是的,它看起来是一样的,但一开始只是“...BEGIN PRIVATE KEY..”。

    由于 OpenSSL 端的默认 RSA 填充是 PKCS1.5 填充

    openssl rsautl -help
    -pkcs Use PKCS#1 v1.5 padding (default)
    

    你应该在 Java 端使用这个实例:

    Cipher decryptCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
    

    您将收到(使用 PKCS8 密钥)加密字符串 Hola Mundo

    【讨论】:

      【解决方案2】:

      在@michael-fehr 的帮助下,我可以让它工作;这是我所做的,以防其他人需要它:

      1. 生成 openssl PKCS8 密钥对:
      openssl genrsa -out keypair.pem 2048
      openssl rsa -in keypair.pem -pubout -out publickey.crt
      openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in keypair.pem -out pkcs8.key
      

      结果现在我有 2 个文件,publickey.crt:

      -----BEGIN PUBLIC KEY-----
      MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxlfy+juJwTDtw8XolfSK
      QB+JaKTgZMl+MjWo+m9n8Kt64ygqtfGvDda1UvT3t9e2ZpOvlsmfSIN0SUMhsq+T
      /O8+Xyr87/sUU7tYocQ6adGh+zO58EecuSUtgutDdwh9/WkVqHhdCjeZXN5310/s
      afaxJJzBemMjvmc/1yiMtBSVrCl71CloR6J1lnz+QZK+zqaNlKIQdQay9PoQlGEL
      RrGgqo8fHdK3OQVUd6Ifzh5G1Mmnv67esCAKyeW8yeb6lQ7dtsJQJEC8M9yn4n1D
      bz0+OwWWTzqHBo8b5JYi6xXnb/0WsaRX/ooWk5BEykmkkBhSmDYx0ZtLZcA2/Pj2
      jwIDAQAB
      -----END PUBLIC KEY-----
      

      和pkcs8.key:

      -----BEGIN PRIVATE KEY-----
      MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDGV/L6O4nBMO3D
      xeiV9IpAH4lopOBkyX4yNaj6b2fwq3rjKCq18a8N1rVS9Pe317Zmk6+WyZ9Ig3RJ
      QyGyr5P87z5fKvzv+xRTu1ihxDpp0aH7M7nwR5y5JS2C60N3CH39aRWoeF0KN5lc
      3nfXT+xp9rEknMF6YyO+Zz/XKIy0FJWsKXvUKWhHonWWfP5Bkr7Opo2UohB1BrL0
      +hCUYQtGsaCqjx8d0rc5BVR3oh/OHkbUyae/rt6wIArJ5bzJ5vqVDt22wlAkQLwz
      3KfifUNvPT47BZZPOocGjxvkliLrFedv/RaxpFf+ihaTkETKSaSQGFKYNjHRm0tl
      wDb8+PaPAgMBAAECggEAWpirnI77cioWQJkyjuQ/DeEZ05mUAZVjti16fMHMWUsK
      e53KPIcjbY/IDRdl2yyF3T7SMm7v+aBJynkGeGboktz4wWGSXU9zTnfBmUpXYCRn
      96T95nnfZVZM/oLVsxZG7ixEv0oTPWp9+8SGOuv/0brj2RRc77k/B2aD65RTCKGc
      iHMqK/mzeLedXrthaBwd0ppkQw1M6YvPw+nx8Mhs/sADKMLUTNkqpu16d+2pOLeU
      DKsvnA8ns6/jfFMMdkJ3mhoIeCfqYJJhosydMebLnt8yUo/3NlNmeRKcqH9qx8zC
      em+0wx9+a1fEgzPvadF1pnmI4n/5VlIn9moZXmO0MQKBgQDkg+4QqJT1upAg2NSQ
      QMagoSECGoCM54aMpTCTDlhrzphW7tms5AjDmfrN/2NQ+LodjBHpqNd6E44D9U+6
      EHBJ/PGOJE1CWdVckAUX+a51g67lmPNrfrFolTT1zrTJNq4VCKFffLUDW9yw+B+0
      9QlWN36LG/jYr3Ia4D59mAgCRwKBgQDeMwTCJDfCMOPtiLT5Xl4J9H76aHU8por0
      4C3fkq/zWCPxxU3XAO6eJQNzEhM8I+Yo/b3WbyzyqM2Ww9Y8qSOD/cpr2ftSdT60
      l7jPSGjAIyudAd3QjkVC+OgwX1cSrfyuiRoyuQiHPyzAoiqK4AKxxUa0EFD8Ec42
      X+mHT3eFeQKBgH13TmvJE9iDcYUHaFY3qpchQO1VvcUfjcmFHVFwq+2tRgldJRj/
      LyyuS311PoODvTRh5qfjM0Psnqnfs8GWKwEEp2AC4ISQrEwhKxrJ1RbikVGwk94u
      dpvUaHqZ3rsnkZcs4OV7pCtO8bIc2dPSQikbWRhp6EyYr86/1q/AnI0bAoGAb5G4
      gu8CnFxGJkAtdsUefOsqUvveWhzZywlBn3AdLxgDvGMwqZOLPRciu0XJKLpx2AVI
      rAJY1GNUD663xO+8qIrnd+4VFptOaAmCv3oBNvCx9n04bn7xYiZvF9LXesaoCM9I
      u01Tbe2XwAXtTJwcXjzLOqCyuU8LdxwDu3B4eCkCgYEAsTQ8Rn6YaCy2cNl/7BZy
      Jfr8tqwKprOeu+tcRg/MxUjjo72PVsK8WiahHHKxpFNlsDa0/u6GlICKUaY9Emul
      Chu20kYr6xFFiczLo9enwiAJ5TDOz8yqOyv/1wALiTayOz2DVTwiax/D45yLJxQ6
      dV0YXCvoOcDjM1c/vDVOK7w=
      -----END PRIVATE KEY-----
      
      1. 现在,让我们使用 publickey.crt 文件将“Hola Mundo”加密为 base64 字符串:
      echo "Hola Mundo" | openssl rsautl -encrypt -pubin -inkey publickey.crt | base64 -w 0
      jeqdFnlj5Rxl8iQcoLc8o0u3KV4950OjSeqJW2ba0P5hcfdkIbtff/WW6rPdFudSYBOr1i+NwQ2jEpRGzOVrJ6mEZI4r/iFAJHkL7a3kQTs+pC1i5nig8MzO+5IU615HZhOykQ1FJfv3+OVOtTj8C5HLDZEehr1ggFPIp10YrYls6Gffxww5xlOZHBbg5J6JBmItmwFmvCl8O5ZI7N9hp5ynqqKYwAHxqRj0UUe1MXyGjEiL9aQdNiYJFCUL5V/0Vq6iP4sLRrU3Ir35fkMAWlQHt4vbmhgX5XUjv1804BIa7HlMytwnN7ZuKnJ6WKnOoJznpYbZOw92yXtKhPfUsA==
      
      1. 现在,使用 Bouncy Castle 库返回“Hola Mundo”的 java 代码:
      import java.io.File;
      import java.io.FileReader;
      import java.security.KeyFactory;
      import java.security.interfaces.RSAPrivateKey;
      import java.security.spec.PKCS8EncodedKeySpec;
      import java.util.Base64;
      
      import javax.crypto.Cipher;
      
      import org.bouncycastle.util.io.pem.PemObject;
      import org.bouncycastle.util.io.pem.PemReader;
      
      public class App {
          public static RSAPrivateKey readPrivateKey(File file) throws Exception {
              KeyFactory factory = KeyFactory.getInstance("RSA");
           
              try (FileReader keyReader = new FileReader(file);
                PemReader pemReader = new PemReader(keyReader)) {
           
                  PemObject pemObject = pemReader.readPemObject();
                  byte[] content = pemObject.getContent();
                  PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(content);
                  return (RSAPrivateKey) factory.generatePrivate(privKeySpec);
              }
          }
          
          public static String getDecrypted(String data, RSAPrivateKey key) throws Exception {
              Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
              
              cipher.init(Cipher.DECRYPT_MODE, key);
              
              byte[] encryptedbytes = cipher.doFinal(Base64.getDecoder().decode(data.getBytes()));
              
              return new String(encryptedbytes);
          }
          
          public static void main(String[] args) {
              String data = "GjoUq7pz6ZV231MlZmBNiWnB7FlOHsGKFmAiMGhSUa9aIkXswnP8Ow4WTYR12tFIdyIeevQWCmEJgebiQ9wpBDLODtT4U00wTxPAfIjulgVhj0MA56b1nDkhCfL6gwzwsD2JxFO8/eMhqY1Wptn/fYn6USfbt7XFRyV73IeFBUvp0OisJ3DXxZsHfpfdL/yQcbGCboiiYEDkJ3DnLhGiaeMuLIedmABLgqWJv8EwPIBT0x/jgIMhaxQSwcs0w/fAYIEt/E4gkOpcFVkiTp6IKDsmiYgzDnXTnPko059Be9mQ3eJ3tIZ+U6Tfm1RCFY7Jr1oTIoZxOgHspgAIQb3U+w==";
              System.out.println("TEXTO CIFRADO:");
              System.out.println(data);
              System.out.println();
      
              
              try {
                  File file = new File("/home/gbasisty/pruebas_openssl/pkcs8.key");
                  RSAPrivateKey key = readPrivateKey(file);
      
                  String texto = getDecrypted(data, key);
                  System.out.println("TEXTO DESCIFRADO:");
                  System.out.println(texto);
                  System.out.println();
              } catch(Exception e) {
                  System.out.println(e);
              }
          }
      }
      

      ...它就像一个魅力。

      再次感谢迈克尔!

      【讨论】:

        猜你喜欢
        • 2014-11-25
        • 2011-07-21
        • 2015-11-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-08-10
        • 2012-01-20
        相关资源
        最近更新 更多