2017-12-18 8 views
0

AES로 문자열을 암호화하고 RSA로 AES 키 getEncoded() 값을 암호화 한 다음 해당 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로 암호화하고 암호 해독하면 올바르게 myString을 암호화하고 해독 할 수 있습니까?"

+0

[RSA 공개 키로 AES 키 암호화] 가능한 복제본 (https://stackoverflow.com/questions/9658921/encrypting-aes-key-with-rsa-public-key) – vinS

+1

@vs 중복되지 않습니다. 그 질문에 대한 대답은 패딩을 사용하는 것이었기 때문에, 나는 사용했지만 아무 소용이 없었습니다. –

답변

1

AES 키가 임의의 바이트를 포함하고 있으며 모든 바이트가 문자 대표가 아니기 때문에 이것은 작동하지 않습니다. Java의 표준 문자열 변환 문제는 인코딩/디코딩 중에 예외를 생성하는 대신 알 수없는 문자와 바이트를 삭제한다는 것입니다.

RSA는 바이트 단위로 작동하므로 키를 문자열로 변환 한 다음 다시 바이트로 변환하면 변환이 손실 될 수 있습니다 (예 : 32 바이트 중 4 개를 삭제).

다른 방법으로 (그리고 아마도 더 나은 경우가 있습니다.) 대신 암호의 래핑 모드를 사용해보십시오. 이것은 일부 하드웨어 솔루션과 호환되어야합니다. 이 경우 getEncoded으로 전화하지 않아도됩니다. 이러한 GCM 같은


OAEP 암호화 및 인증 암호화 모드는 PKCS # 1의 패딩 (태양 공급자 기본값) 및 CBC 모드 암호화 선호한다.

+0

('StandardCharsets'의) 문자 세트를 나타내지 않고'new String' 또는'getBytes'를 절대 사용하지 마십시오. –

+0

물론 캐릭터 세트를 명시 적으로 정의하지 않는 다른 플랫폼 특정 코드와 통신해야하는 경우가 아니라면. –