2017-12-18 44 views
0

AESで文字列を暗号化し、AESキーのgetEncoded()値をRSAで暗号化し、そのAES getEncoded()値を復号してオリジナルを取得する文字列。公開鍵はユーザー証明書からロードされ、秘密鍵はファイルからロードされます。 コードを以下に示します。RSAでエンコードされたAESキーからAESキーを生成する

public class Main { 

public static void main(String[] args) throws Exception { 
String myString = "My Message"; 
    KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); 
    keyGenerator.init(128); 

    SecretKey secretKey = keyGenerator.generateKey(); 

    byte[] initializationVector = new byte[128/8];//16 
    SecureRandom prng = new SecureRandom(); 
    prng.nextBytes(initializationVector); 

    Cipher AESCipherForEncryption = Cipher.getInstance("AES/CBC/PKCS5PADDING"); 

    AESCipherForEncryption.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(initializationVector)); 

    byte[] byteVersionOfMyMessage = myString.getBytes(); 
    byte[] byteVersionOfCipherText = AESCipherForEncryption.doFinal(byteVersionOfMyMessage); 
    String cipherText = new BASE64Encoder().encode(byteVersionOfCipherText); 

    InputStream in1 = new FileInputStream("user.crt"); 
    CertificateFactory cf1 = CertificateFactory.getInstance("X509"); 
    Certificate c1 = cf1.generateCertificate(in1); 
    X509Certificate toSendcert = (X509Certificate) c1; 
    PublicKey publicKey = toSendcert.getPublicKey(); 
    String cipherTextRSA = encryptRSA(publicKey, new String(secretKey.getEncoded())); 

    String decypheredRSA = decryptRSA(getPrivateKey("user.pk8", "RSA"), cipherTextRSA); 
    System.out.println(cipherTextRSA); 
    System.out.println(decypheredRSA); 

    SecretKey originalKey = new SecretKeySpec(new String(decypheredRSA.getBytes("UTF-8")).getBytes(), 0, new String(decypheredRSA.getBytes("UTF-8")).getBytes().length, "AES"); 

    Cipher AESCipherForDecryption = Cipher.getInstance("AES/CBC/PKCS5PADDING"); 
    AESCipherForDecryption.init(Cipher.DECRYPT_MODE, originalKey, new IvParameterSpec(initializationVector)); 
    byte[] byteVersionOfDecriptedText = AESCipherForDecryption.doFinal(new BASE64Decoder().decodeBuffer(cipherText)); 
    String decMessage = new String(byteVersionOfDecriptedText); 
    System.out.println(decMessage); 
} 
public static String encryptRSA(PublicKey pubKey, String message) throws Exception { 
    Cipher cipher = Cipher.getInstance("RSA"); 
    cipher.init(Cipher.ENCRYPT_MODE, pubKey); 
    Base64.Encoder encoder = Base64.getEncoder(); 
    String encryptedString = encoder.encodeToString(cipher.doFinal(message.getBytes("UTF-8"))); 
    return encryptedString; 
} 

public static PrivateKey getPrivateKey(String filename, String algorithm) throws Exception { 
    File f = new File(filename); 
    FileInputStream fis = new FileInputStream(f); 
    DataInputStream dis = new DataInputStream(fis); 
    byte[] keyBytes = new byte[(int) f.length()]; 
    dis.readFully(keyBytes); 
    dis.close(); 

    String temp = new String(keyBytes); 
    String privKeyPEM = temp.replace("-----BEGIN PRIVATE KEY-----", ""); 
    privKeyPEM = privKeyPEM.replace("-----END PRIVATE KEY-----", ""); 
    privKeyPEM = privKeyPEM.replace("\n", ""); 

    byte[] decoded = Base64.getDecoder().decode(privKeyPEM); 

    PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(decoded); 
    KeyFactory kf = KeyFactory.getInstance(algorithm); 
    return kf.generatePrivate(spec); 
} 

public static String decryptRSA(PrivateKey prKey, String encrypted) throws Exception { 
    Base64.Decoder decoder = Base64.getDecoder(); 
    byte[] input = decoder.decode(encrypted); 
    Cipher cipher = Cipher.getInstance("RSA"); 
    cipher.init(Cipher.DECRYPT_MODE, prKey); 

    return new String(cipher.doFinal(input)); 
} 

私は入れませんエラーは、次のとおりです。

Exception in thread "main" java.security.InvalidKeyException: Invalid AES key length: 28 bytes 
    at com.sun.crypto.provider.AESCipher.engineGetKeySize(AESCipher.java:509) 
    at javax.crypto.Cipher.passCryptoPermCheck(Cipher.java:1067) 
    at javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1038) 
    at javax.crypto.Cipher.implInit(Cipher.java:805) 
    at javax.crypto.Cipher.chooseProvider(Cipher.java:864) 
    at javax.crypto.Cipher.init(Cipher.java:1396) 
    at javax.crypto.Cipher.init(Cipher.java:1327) 
    at com.company.Main.main(Main.java:79) 

私は暗号化と復号secretKey.getEncoded()値を、そしてちょうどそれが正常に動作するRSAせずにAESを使用しない場合。また、公開鍵を使って文字列を暗号化し、秘密鍵で復号化すれば、RSAで作業します。私の質問は「secretKey.getEncoded()の値をRSAで適切に暗号化して解読することができるので、私は適切に暗号化して復号化することができますか?」

+0

[AES鍵をRSA公開鍵で暗号化する]の可能な複製(https://stackoverflow.com/questions/9658921/encrypting-aes-key-with-rsa-public-key) – vinS

+1

@vinS重複しないその質問への答えは私が使用しているが無駄なパディングを使用することだったので、 –

答えて

1
new String(secretKey.getEncoded()) 

AESキーにはランダムなバイトが含まれており、すべてのバイトが文字の代表ではないため、これは機能しません。 Javaでの標準文字列変換の問題は、エンコーディング/デコード中に例外を生成する代わりに、未知の文字とバイトを削除することです。

RSAはバイトで動作しますが、キーを文字列に変換してから再び変換する必要があります(32バイトのうち4つを削除するなど)。

また、暗号化のラッピングモードを試してみてください。これは、いくつかのハードウェアソリューションと互換性があるはずです。その場合はgetEncodedに電話する必要はありません。このようGCMなど


OAEPの暗号化および認証された暗号化モードは、PKCS#1パディング(Sunのプロバイダのデフォルト)とCBCモードの暗号化よりも優先されなければなりません。

+0

'(StandardCharsets'の)文字セットを示さずに決して' new String'または 'getBytes'を使用してはいけません。 –

+0

もちろん、文字セットを明示的に定義していない他のプラットフォーム固有のコードと通信する必要がある場合を除きます。 –

関連する問題