【问题标题】:Issues in RSA encryption in Java classJava 类中的 RSA 加密问题
【发布时间】:2012-02-01 10:32:45
【问题描述】:
public class MyEncrypt {

    public void saveToFile(String fileName, BigInteger mod, BigInteger exp) throws IOException {
        ObjectOutputStream oout = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(fileName)));
          try {
                oout.writeObject(mod);
                oout.writeObject(exp);
          } catch (Exception e) {
          throw new IOException("Unexpected error", e);
          } finally {
            oout.close();
          }
    }

    public static void main(String[] args) throws Exception {
                MyEncrypt myEncrypt = new MyEncrypt();
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
        kpg.initialize(128);
        KeyPair kp = kpg.genKeyPair();
        RSAPublicKey publicKey = (RSAPublicKey) kp.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) kp.getPrivate();
        KeyFactory fact = KeyFactory.getInstance("RSA");        
        RSAPublicKeySpec pub = fact.getKeySpec(kp.getPublic(), RSAPublicKeySpec.class);
        RSAPrivateKeySpec priv = fact.getKeySpec(kp.getPrivate(), RSAPrivateKeySpec.class);

        myEncrypt.saveToFile("public.key", pub.getModulus(), pub.getPublicExponent());
        myEncrypt.saveToFile("private.key", priv.getModulus(), priv.getPrivateExponent());
        String encString = myEncrypt.bytes2String(myEncrypt.rsaEncrypt("pritesh".getBytes()));
        System.out.println("encrypted : " + encString);
        String decString = myEncrypt.bytes2String(myEncrypt.rsaDecrypt(encString.getBytes()));
        System.out.println("decrypted : " + decString);
    }   

    PublicKey readKeyFromFile(String keyFileName) throws Exception {
      InputStream in = new FileInputStream(keyFileName);
      ObjectInputStream oin = new ObjectInputStream(new BufferedInputStream(in));
      try {
        BigInteger m = (BigInteger) oin.readObject();
        BigInteger e = (BigInteger) oin.readObject();
        RSAPublicKeySpec keySpec = new RSAPublicKeySpec(m, e);
        KeyFactory fact = KeyFactory.getInstance("RSA");
        PublicKey pubKey = fact.generatePublic(keySpec);
        return pubKey;
      } catch (Exception e) {
        throw new RuntimeException("Spurious serialisation error", e);
      } finally {
        oin.close();
      }
    }

    PrivateKey readPrivateKeyFromFile(String keyFileName) throws Exception {
      InputStream in = new FileInputStream(keyFileName);
      ObjectInputStream oin = new ObjectInputStream(new BufferedInputStream(in));
      try {
        BigInteger m = (BigInteger) oin.readObject();
        BigInteger e = (BigInteger) oin.readObject();
        RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(m, e);
        KeyFactory fact = KeyFactory.getInstance("RSA");
        PrivateKey pubKey = fact.generatePrivate(keySpec);
        return pubKey;
      } catch (Exception e) {
        throw new RuntimeException("Spurious serialisation error", e);
      } finally {
        oin.close();
      }
    }

    public byte[] rsaEncrypt(byte[] data) throws Exception {
      byte[] src = new byte[] { (byte) 0xbe, (byte) 0xef };
      PublicKey pubKey = this.readKeyFromFile("public.key");
      Cipher cipher = Cipher.getInstance("RSA");
      cipher.init(Cipher.ENCRYPT_MODE, pubKey);
      byte[] cipherData = cipher.doFinal(data);
      return cipherData;
    }

    public byte[] rsaDecrypt(byte[] data) throws Exception {
      byte[] src = new byte[] { (byte) 0xbe, (byte) 0xef };
      PrivateKey pubKey = this.readPrivateKeyFromFile("private.key");
      Cipher cipher = Cipher.getInstance("RSA");
      cipher.init(Cipher.DECRYPT_MODE, pubKey);
      byte[] cipherData = cipher.doFinal(data);
      return cipherData;
    }

    private String bytes2String(byte[] bytes) {
        StringBuilder string = new StringBuilder();
        for (byte b: bytes) {
                String hexString = Integer.toHexString(0x00FF & b);
                string.append(hexString.length() == 1 ? "0" + hexString : hexString);
        }
        return string.toString();
    }
}

我收到此错误:

Exception in thread "main" java.security.InvalidParameterException: RSA keys must be at least 512 bits long
    at sun.security.rsa.RSAKeyPairGenerator.initialize(RSAKeyPairGenerator.java:70)
    at java.security.KeyPairGenerator$Delegate.initialize(KeyPairGenerator.java:631)
    at java.security.KeyPairGenerator.initialize(KeyPairGenerator.java:340)
    at MyEncrypt.main(MyEncrypt.java:42)

我已经从http://www.javamex.com/tutorials/cryptography/rsa_encryption_2.shtml 示例中创建了这个类


公共类 MyEncrypt {

static final String HEXES = "0123456789ABCDEF"; 
byte[] buf = new byte[1024];      

public void saveToFile(String fileName, BigInteger mod, BigInteger exp) throws IOException {
    ObjectOutputStream oout = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(fileName)));
      try {
            oout.writeObject(mod);
            oout.writeObject(exp);
      } catch (Exception e) {
      throw new IOException("Unexpected error", e);
      } finally {
        oout.close();
      }
}

public static void main(String[] args) throws Exception {       
            MyEncrypt myEncrypt = new MyEncrypt();
    KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
    kpg.initialize(2048);
    KeyPair kp = kpg.genKeyPair();
    RSAPublicKey publicKey = (RSAPublicKey) kp.getPublic();
    RSAPrivateKey privateKey = (RSAPrivateKey) kp.getPrivate();
    KeyFactory fact = KeyFactory.getInstance("RSA");        
    RSAPublicKeySpec pub = fact.getKeySpec(kp.getPublic(), RSAPublicKeySpec.class);
    RSAPrivateKeySpec priv = fact.getKeySpec(kp.getPrivate(), RSAPrivateKeySpec.class);

    myEncrypt.saveToFile("public.key", pub.getModulus(), pub.getPublicExponent());
    myEncrypt.saveToFile("private.key", priv.getModulus(), priv.getPrivateExponent());
    String encString = myEncrypt.rsaEncrypt("pritesh");
    System.out.println("encrypted : " + encString);
    String decString = myEncrypt.rsaDecrypt(encString);
    System.out.println("decrypted : " + decString);

    String main_file_path = "resume.doc";                
    String main_encrypt_file_path = "encrypt.doc";
    String main_decrypt_file_path = "decrypt.doc";

    myEncrypt.rsaEncrypt(new FileInputStream(main_file_path),new FileOutputStream(main_encrypt_file_path));
            // Decrypt
    myEncrypt.rsaDecrypt(new FileInputStream(main_encrypt_file_path),new FileOutputStream(main_decrypt_file_path));
}   

PublicKey readKeyFromFile(String keyFileName) throws Exception {
  InputStream in = new FileInputStream(keyFileName);
  ObjectInputStream oin = new ObjectInputStream(new BufferedInputStream(in));
  try {
    BigInteger m = (BigInteger) oin.readObject();
    BigInteger e = (BigInteger) oin.readObject();
    RSAPublicKeySpec keySpec = new RSAPublicKeySpec(m, e);
    KeyFactory fact = KeyFactory.getInstance("RSA");
    PublicKey pubKey = fact.generatePublic(keySpec);
    return pubKey;
  } catch (Exception e) {
    throw new RuntimeException("Spurious serialisation error", e);
  } finally {
    oin.close();
  }
}

PrivateKey readPrivateKeyFromFile(String keyFileName) throws Exception {
  InputStream in = new FileInputStream(keyFileName);
  ObjectInputStream oin = new ObjectInputStream(new BufferedInputStream(in));
  try {
    BigInteger m = (BigInteger) oin.readObject();
    BigInteger e = (BigInteger) oin.readObject();
    RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(m, e);
    KeyFactory fact = KeyFactory.getInstance("RSA");
    PrivateKey pubKey = fact.generatePrivate(keySpec);
    return pubKey;
  } catch (Exception e) {
    throw new RuntimeException("Spurious serialisation error", e);
  } finally {
    oin.close();
  }
}

public String rsaEncrypt(String plaintext) throws Exception {      
  PublicKey pubKey = this.readKeyFromFile("public.key");
  Cipher cipher = Cipher.getInstance("RSA");
  cipher.init(Cipher.ENCRYPT_MODE, pubKey);
  byte[] ciphertext = cipher.doFinal(plaintext.getBytes("UTF-8"));
  return this.byteToHex(ciphertext);
}

public void rsaEncrypt(InputStream in, OutputStream out) throws Exception {
    try {                    
        PublicKey pubKey = this.readKeyFromFile("public.key");
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, pubKey); 
        // Bytes written to out will be encrypted
        out = new CipherOutputStream(out, cipher);

        // Read in the cleartext bytes and write to out to encrypt
        int numRead = 0;
        while ((numRead = in.read(buf)) >= 0){
            out.write(buf, 0, numRead);
        }
        out.close();
    }
    catch (java.io.IOException e){
        e.printStackTrace();
    }
}

public void rsaDecrypt(InputStream in, OutputStream out) throws Exception {
    try {                 
        PrivateKey pubKey = this.readPrivateKeyFromFile("private.key");
        Cipher dcipher = Cipher.getInstance("RSA");
        dcipher.init(Cipher.DECRYPT_MODE, pubKey);
        // Bytes read from in will be decrypted
        in = new CipherInputStream(in, dcipher);

        // Read in the decrypted bytes and write the cleartext to out
        int numRead = 0;
        while ((numRead = in.read(buf)) >= 0) {
            out.write(buf, 0, numRead);
        }
        out.close();
    } catch (java.io.IOException e) {
         e.printStackTrace();
    }
}

public String rsaDecrypt(String hexCipherText) throws Exception {      
  PrivateKey pubKey = this.readPrivateKeyFromFile("private.key");
  Cipher cipher = Cipher.getInstance("RSA");
  cipher.init(Cipher.DECRYPT_MODE, pubKey);      
  String plaintext = new String(cipher.doFinal(this.hexToByte(hexCipherText)), "UTF-8");
  return plaintext;
}

public static String byteToHex( byte [] raw ) {
    if ( raw == null ) {
      return null;
    }
    final StringBuilder hex = new StringBuilder( 2 * raw.length );
    for ( final byte b : raw ) {
      hex.append(HEXES.charAt((b & 0xF0) >> 4))
         .append(HEXES.charAt((b & 0x0F)));
    }
    return hex.toString();
}

public static byte[] hexToByte( String hexString){
    int len = hexString.length();
    byte[] ba = new byte[len / 2];
    for (int i = 0; i < len; i += 2) {
        ba[i/2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4) + Character.digit(hexString.charAt(i+1), 16));
    }
    return ba;
}

}

它适用于文本文件,但对 docx 和视频等文件有任何想法吗?

【问题讨论】:

  • 获取更长的密钥——准确地说是 512 位。
  • +1 获取完整的工作示例

标签: java encryption cryptography rsa


【解决方案1】:

错误说明了一切:您正在使用 128 的密钥集进行初始化,而 RSA 预计至少为 512。

【讨论】:

  • 教程页面的底部谈到了密钥长度,我不确定你从哪里得到 128,因为任何地方都没有提到。 javamex.com/tutorials/cryptography/rsa_key_length.shtml
  • 但是当我使用 512 时,线程“main”javax.crypto.IllegalBlockSizeException 中出现此错误异常:数据不得超过 64 个字节
  • 我可以回答,但因为它与组织无关。问题,您可能想创建一个新的。
  • @ShashankKadne 您无需对数据进行编码即可使用 RSA 私钥对其进行加密。在这种情况下,它甚至会适得其反。
  • @KurtDuBois 密钥集 -> 密钥大小(以位为单位)?
【解决方案2】:

你有不止一个问题:

  1. Java 不支持大小小于 512 的 RSA 密钥。2048 位是更好的选择。所以改变密钥长度:

    kpg.initialize(2048);
    
  2. String.getBytes() 不是您的 bytes2String() 的逆运算。加密后,您将字节转换为十六进制字符串。但是你在解密之前将这个十六进制字符串转换为它的 ASCII 表示,这会产生一个太长的字节数组。相反,使用类似这样的东西将十六进制字符串转换回来:

    private byte[] string2bytes(String s) {
        int len = s.length();
        byte[] res = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            res[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                            + Character.digit(s.charAt(i+1), 16));
        }
        return res;
    }
    

    然后调用它而不是 String.getBytes():

    // Note, this line is not completely fixed yet
    String decString = 
      myEncrypt.bytes2String(
        myEncrypt.rsaDecrypt(
          myEncrypt.string2bytes(encString)
        )
      );
    
  3. 最后你遇到了相反的问题。您的 bytes2String() 方法不会反转 String.getBytes() 操作。您加密了“pritesh”.getBytes() 的输出,这就是您从解密操作中得到的结果。现在您必须将其转换回字符串。 String(byte[])-constructor 会为你做这些:

    String decString = 
      new String(
        myEncrypt.rsaDecrypt(
          myEncrypt.string2bytes(encString)
        )
      );
    

【讨论】:

  • 是的,我按照你说的进行了更改并开始工作,但是另一个问题
【解决方案3】:

最终答案

public class MyEncrypt {

public static final int AES_Key_Size = 128;

Cipher pkCipher, aesCipher;
byte[] aesKey;
SecretKeySpec aeskeySpec;

public static void main(String[] args) throws Exception {
    //MyEncrypt.createRSAKeys(); //call to generated RSA keys
    MyEncrypt secure = new MyEncrypt();
    // to encrypt a file
    secure.makeKey();
    secure.saveKey(new File("keys/ase.key"), "keys/public.key");
    secure.encrypt(new File("test/sample.pdf"), new File("test/encrypt_sample.pdf"));

    // to decrypt it again
    secure.loadKey(new File("keys/ase.key"), "keys/private.key");
    secure.decrypt(new File("test/encrypt_sample.pdf"), new File("test/decrypted_sample.pdf"));
}

/**
* Constructor: creates ciphers
*/
public MyEncrypt() throws GeneralSecurityException {
    // create RSA public key cipher
    pkCipher = Cipher.getInstance("RSA");
    // create AES shared key cipher
    aesCipher = Cipher.getInstance("AES");
}

public static void createRSAKeys() throws Exception {
    KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
    kpg.initialize(512);
    KeyPair kp = kpg.genKeyPair();
    RSAPublicKey publicKey = (RSAPublicKey) kp.getPublic();
    RSAPrivateKey privateKey = (RSAPrivateKey) kp.getPrivate();
    KeyFactory fact = KeyFactory.getInstance("RSA");        
    RSAPublicKeySpec pub = fact.getKeySpec(kp.getPublic(), RSAPublicKeySpec.class);
    RSAPrivateKeySpec priv = fact.getKeySpec(kp.getPrivate(), RSAPrivateKeySpec.class);
    saveToFile("keys/public.key", pub.getModulus(), pub.getPublicExponent());
    saveToFile("keys/private.key", priv.getModulus(), priv.getPrivateExponent());
    System.out.println("RSA public & private keys are generated");
}

private static void saveToFile(String fileName, BigInteger mod, BigInteger exp) throws IOException {
    ObjectOutputStream oout = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(fileName)));
      try {
            oout.writeObject(mod);
            oout.writeObject(exp);
      } catch (Exception e) {
      throw new IOException("Unexpected error", e);
      } finally {
        oout.close();
      }
}

/**
* Creates a new AES key
*/
public void makeKey() throws NoSuchAlgorithmException {
    KeyGenerator kgen = KeyGenerator.getInstance("AES");
    kgen.init(AES_Key_Size);
    SecretKey key = kgen.generateKey();
    aesKey = key.getEncoded();
    aeskeySpec = new SecretKeySpec(aesKey, "AES");
}

/**
* Encrypts the AES key to a file using an RSA public key
*/
public void saveKey(File out, String publicKeyFile) throws IOException, GeneralSecurityException {
        try {
            // read public key to be used to encrypt the AES key
            byte[] encodedKey = new byte[(int)publicKeyFile.length()];
            new FileInputStream(publicKeyFile).read(encodedKey);

            // create public key
            //X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(encodedKey);
            //KeyFactory kf = KeyFactory.getInstance("RSA");
            //PublicKey pk = kf.generatePublic(publicKeySpec);
            PublicKey pk = this.readPublicKeyFromFile(publicKeyFile);

            // write AES key
            pkCipher.init(Cipher.ENCRYPT_MODE, pk);
            CipherOutputStream os = new CipherOutputStream(new FileOutputStream(out), pkCipher);
            os.write(aesKey);
            os.close();    
        } catch (Exception e) {
            //throw new Exception("Saving key exception", e);    
        }

}

private PublicKey readPublicKeyFromFile(String keyFileName) throws Exception {
  InputStream in = new FileInputStream(keyFileName);
  ObjectInputStream oin = new ObjectInputStream(new BufferedInputStream(in));
  try {
    BigInteger m = (BigInteger) oin.readObject();
    BigInteger e = (BigInteger) oin.readObject();
    RSAPublicKeySpec keySpec = new RSAPublicKeySpec(m, e);
    KeyFactory fact = KeyFactory.getInstance("RSA");
    PublicKey pubKey = fact.generatePublic(keySpec);
    return pubKey;
  } catch (Exception e) {
    throw new RuntimeException("Spurious serialisation error", e);
  } finally {
    oin.close();
  }
}

private PrivateKey readPrivateKeyFromFile(String keyFileName) throws Exception {
  InputStream in = new FileInputStream(keyFileName);
  ObjectInputStream oin = new ObjectInputStream(new BufferedInputStream(in));
  try {
    BigInteger m = (BigInteger) oin.readObject();
    BigInteger e = (BigInteger) oin.readObject();
    RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(m, e);
    KeyFactory fact = KeyFactory.getInstance("RSA");
    PrivateKey pubKey = fact.generatePrivate(keySpec);
    return pubKey;
  } catch (Exception e) {
    throw new RuntimeException("Spurious serialisation error", e);
  } finally {
    oin.close();
  }
}

/**
* Decrypts an AES key from a file using an RSA private key
*/
public void loadKey(File in, String privateKeyFile) throws GeneralSecurityException, IOException {
            try {
                // read private key to be used to decrypt the AES key
               byte[] encodedKey = new byte[(int)privateKeyFile.length()];
               new FileInputStream(privateKeyFile).read(encodedKey);

               // create private key
               //PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(encodedKey);
               //KeyFactory kf = KeyFactory.getInstance("RSA");
               //PrivateKey pk = kf.generatePrivate(privateKeySpec);
               PrivateKey pk = this.readPrivateKeyFromFile(privateKeyFile);

               // read AES key
               pkCipher.init(Cipher.DECRYPT_MODE, pk);
               aesKey = new byte[AES_Key_Size/8];
               CipherInputStream is = new CipherInputStream(new FileInputStream(in), pkCipher);
               is.read(aesKey);
               aeskeySpec = new SecretKeySpec(aesKey, "AES");     
            } catch (Exception e) {

            }

   }

/**
 * Encrypts and then copies the contents of a given file.
 */
public void encrypt(File in, File out) throws IOException, InvalidKeyException {
    aesCipher.init(Cipher.ENCRYPT_MODE, aeskeySpec);

    FileInputStream is = new FileInputStream(in);
    CipherOutputStream os = new CipherOutputStream(new FileOutputStream(out), aesCipher);

    copy(is, os);

    os.close();
}

/**
 * Decrypts and then copies the contents of a given file.
 */
public void decrypt(File in, File out) throws IOException, InvalidKeyException {
    aesCipher.init(Cipher.DECRYPT_MODE, aeskeySpec);

    CipherInputStream is = new CipherInputStream(new FileInputStream(in), aesCipher);
    FileOutputStream os = new FileOutputStream(out);

    copy(is, os);

    is.close();
    os.close();
}

/**
 * Copies a stream.
 */
private void copy(InputStream is, OutputStream os) throws IOException {
    int i;
    byte[] b = new byte[1024];
    while((i=is.read(b))!=-1) {
        os.write(b, 0, i);
    }
}

}

【讨论】:

    猜你喜欢
    • 2011-06-23
    • 1970-01-01
    • 2011-01-29
    • 2012-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多