Проблемы в шифровании RSA в классе Java - PullRequest
1 голос
/ 01 февраля 2012
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 пример


</p> <p>public class MyEncrypt {</p> <pre><code>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 и видео?

Ответы [ 3 ]

3 голосов
/ 01 февраля 2012

Ошибка говорит сама за себя: вы инициализируете с набором ключей 128, а RSA ожидает минимум 512.

0 голосов
/ 03 февраля 2012

Финал и

public class MyEncrypt {</p> <pre><code>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); } }

}

0 голосов
/ 02 февраля 2012

У вас более одной проблемы:

  1. Java не поддерживает ключи RSA размером менее 512. 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 []) сделает это за вас:

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