2011-07-04 4 views
13

RSA 알고리즘을 사용하여 .NET에서 문자열을 암호화하고 Java에서 결과를 해독하려고합니다. 현재로서는 반대 방향 (Java에서 암호화, .NET에서 암호 해독)을 수행 할 수있었습니다. 여기 나는 실제로 작동하는 내 코드 (자바 암호화)가 :RSA .NET 암호화 Java 암호 해독

byte[] modulusBytes = Base64.decode("2rRVVVFJRbH/wAPDtnwZwu+nxU+AZ6uXxh/sW+AMCBogg7vndZsnRiHoLttYYPqOyOhfgaBOQogrIfrKL4lipK4m52SBzw/FfcM9DsKs/rYR83tBLiIAfgdnVjF27tZID+HJMFTiI30mALjr7+tfp+2lIACXA1RIKTk7S9pDmX8="); 
byte[] exponentBytes = Base64.decode("AQAB"); 
BigInteger modulus = new BigInteger(1, modulusBytes); 
BigInteger exponent = new BigInteger(1, exponentBytes); 

RSAPublicKeySpec rsaPubKey = new RSAPublicKeySpec(modulus, exponent); 
KeyFactory fact = KeyFactory.getInstance("RSA"); 
PublicKey pubKey = fact.generatePublic(rsaPubKey); 

Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); 
cipher.init(Cipher.ENCRYPT_MODE, pubKey); 

byte[] plainBytes = new String("big kitty dancing").getBytes("UTF-8"); 
byte[] cipherData = cipher.doFinal(plainBytes); 
String encryptedString = Base64.encode(cipherData); 
return encryptedString; 

그리고 (.NET 암호 해독)

const int PROVIDER_RSA_FULL = 1; 
const string CONTAINER_NAME = "Tracker"; 

CspParameters cspParams; 
cspParams = new CspParameters(PROVIDER_RSA_FULL); 
cspParams.KeyContainerName = CONTAINER_NAME; 
RSACryptoServiceProvider rsa1 = new RSACryptoServiceProvider(cspParams); 
rsa1.FromXmlString("<RSAKeyValue><Modulus>2rRVVVFJRbH/wAPDtnwZwu+nxU+AZ6uXxh/sW+AMCBogg7vndZsnRiHoLttYYPqOyOhfgaBOQogrIfrKL4lipK4m52SBzw/FfcM9DsKs/rYR83tBLiIAfgdnVjF27tZID+HJMFTiI30mALjr7+tfp+2lIACXA1RIKTk7S9pDmX8=</Modulus><Exponent>AQAB</Exponent><P>+lXMCEwIN/7+eMpBrq87kQppxu3jJBTwztGTfXNaPUTx+A6uqRwug5oHBbSpYXKNDNCBzVm/0VxB3bo4FJx+ZQ==</P><Q>yasOGaJaE9xlF9T2xRuKeG9ZxCiyjhYaYB/mbtL+SIbtkRLi/AxaU4g2Il/UxhxhSXArKxIzV28zktispPJx1Q==</Q><DP>ueRgQIEFUV+fY979a1RgrVHIPpqEI1URhOMH3Q59oiXCcOumM5njyIHmWQxRAzXnG+7xlKXi1PrnRll0L4oOKQ==</DP><DQ>dfEMNgG1HJhwpxdtmqkYuoakwQvsIRzcIAuIAJh1DoWaupWJGk8/JEstHb1d+t7uJrzrAi2KyT/HscH2diE0YQ==</DQ><InverseQ>YoYF9PF6FiC0YngVeaC/eqt/ea8wMYNN3YO1LuzWpcy2exPRj2U0ZbWMvHXMUb4ea2qmhZGx1QlK4ULAuWKpXQ==</InverseQ><D>g1WAWI4pEK9TA7CA2Yyy/2FzzNiu0uQCuE2TZYRNiomo96KQXpxwqAzZLw+VDXfJMypwDMAVZe/SqzSJnFEtZxjdxaEo3VLcZ1mnbIL0vS7D6iFeYutF9kF231165qGd3k2tgymNMMpY7oYKjS11Y6JqWDU0WE5hjS2X35iG6mE=</D></RSAKeyValue>"); 

string data2Decrypt = "BaB21vY+RD/jiY3AAsb269fIWTEH38s0xLUfJ7CoVUgaQ6vYzB0tiJ1Ag9HNEdCcuZdGchhqnms8jpsqsHC1iKrz6QCLsgUU7VNWDfQqZYR6Rl/GwR0biK2STnOL+g06f/JUdixHOHOgROify1m8qppYo5plpOVMqYFzEMREMkM="; 

byte[] encyrptedBytes = Convert.FromBase64String(data2Decrypt); 

byte[] plain = rsa1.Decrypt(encyrptedBytes, false); 
string decryptedString = System.Text.Encoding.UTF8.GetString(plain); 
Console.WriteLine("SALIDA: " + decryptedString); 

가 지금은 반대를하고 싶어 ...하지만 몇 가지 오류와 같은를 얻을 수 (키의 크기는 128 바이트 여야합니다 ... 등) 어떻게해야합니까? 당신 요구가 일부 코드 조각이 토끼다시피

.NET

public string Encrypt(string text) 
{ 
    const int PROVIDER_RSA_FULL = 1; 
    const string CONTAINER_NAME = "Tracker"; 

    CspParameters cspParams; 
    cspParams = new CspParameters(PROVIDER_RSA_FULL); 
    cspParams.KeyContainerName = CONTAINER_NAME; 
    RSACryptoServiceProvider rsa1 = new RSACryptoServiceProvider(cspParams); 
    rsa1.FromXmlString("<RSAKeyValue><Modulus>2rRVVVFJRbH/wAPDtnwZwu+nxU+AZ6uXxh/sW+AMCBogg7vndZsnRiHoLttYYPqOyOhfgaBOQogrIfrKL4lipK4m52SBzw/FfcM9DsKs/rYR83tBLiIAfgdnVjF27tZID+HJMFTiI30mALjr7+tfp+2lIACXA1RIKTk7S9pDmX8=</Modulus><Exponent>AQAB</Exponent><P>92jJJyzFBSx6gL4Y1YpALmc5CNjoE/wETjqb3ci2v0+3rZWvJKmKy1ZEdlXpyuvXVksJ6cMdUpNAkMknUk9pTQ==</P><Q>4kxkABZOXyDLryYGCGY0b8N0FIdu5BTCFDYEdcatxl/f7ZGDS1NgHJpUWxkVXFfHy2Y/GuDOIbpcwlsO739H+w==</Q><DP>5bNFvrdUHF+VRN45VFjNCcgQLeSkY5mBrdfASoNFGA29LM5iE5nNIMfxPCS7sQiRnq6Af6YFHVtVgJchiMvtqQ==</DP><DQ>j+ng1qVY5epnXlWiFIla45C7K6sNfIMvAcdwgq39KWEjeWPGyYqWXtpOtzh2eylf6Bx4GVHKBW0NPJTIJMsfLQ==</DQ><InverseQ>8uu0dfPVDqB2qFM1Vdi8hl+2uZtN7gjT2co1cEWy29HVYBZD0k9KKCf2PbkeuSfpgFpE70wW5Hrp8V7l/SwSOw==</InverseQ><D>MM/c18zroJ2Iqi9s5/asvUBF3pjO3NSEbFjFpP/NT6WdKimvECWPz2xT6NlV0Vc6tQaAAmtn7Bt+HPhfVdrA4/ysYVe3/6TWkPjW+bvAhMWu/ZqISx11/jPYSGD9g3ZXgUiqcQM8UbOjlswoq4fpheEXTB0xdVutDLpO3qgHN6k=</D></RSAKeyValue>"); 

    System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding(); 
    byte[] textBytes = encoding.GetBytes(text); 
    byte[] encryptedOutput = rsa1.Encrypt(textBytes, false); 
    string outputB64 = Convert.ToBase64String(encryptedOutput); 
    Console.WriteLine(outputB64); 
    return outputB64; 
} 

자바

public static String Decrypt(String encodedString) throws IllegalBlockSizeException, UnsupportedEncodingException, InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, BadPaddingException 
{ 
    byte[] modulusBytes = Base64.decode("2rRVVVFJRbH/wAPDtnwZwu+nxU+AZ6uXxh/sW+AMCBogg7vndZsnRiHoLttYYPqOyOhfgaBOQogrIfrKL4lipK4m52SBzw/FfcM9DsKs/rYR83tBLiIAfgdnVjF27tZID+HJMFTiI30mALjr7+tfp+2lIACXA1RIKTk7S9pDmX8="); 
    byte[] exponentBytes = Base64.decode("AQAB"); 
    BigInteger modulus = new BigInteger(1, modulusBytes); 
    BigInteger exponent = new BigInteger(1, exponentBytes); 

    RSAPrivateKeySpec rsaPrivKey = new RSAPrivateKeySpec(modulus, exponent); 
    KeyFactory fact = KeyFactory.getInstance("RSA"); 
    PrivateKey privKey = fact.generatePrivate(rsaPrivKey); 

    Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); 
    cipher.init(Cipher.DECRYPT_MODE, privKey); 

    byte[] base64String = Base64.decode(encodedString); 
    byte[] plainBytes = new String(base64String).getBytes("UTF-8"); 
    byte[] cipherData = cipher.doFinal(plainBytes); 

    System.out.println(cipherData); 
    return cipherData.toString(); 
} 
+0

스택 추적을 제공하십시오. 같은 패딩 방식을 지정하고 있습니까? Java에서 .NET 해독을 암호화 할 수 있으며 그 반대도 마찬가지입니다. 비록 내가 PKCS5Padding (Java) 및 PKCS7 (.Net)을 사용하고 하드 코드 키를 사용하지는 않지만. –

+0

내가 얻을 수있는 오류가 다양하기 때문에 나는 추적 할 수 없습니다 (키의 크기를 말하면서 패딩 예외가 발생했습니다 : javax.crypto.BadPaddingException : 데이터가 0으로 시작해야 함) ... 일하지만, 지금은 그 일을하고 있습니다. 만약 당신이 그것을하는 방법을 게시 할 수 있다면, 나는 다음 며칠간이 문제를 해결하는 것이 중요하기 때문에 매우 감사 할 것입니다 ... – Reixons

답변

8

마지막 몇 줄. 이 줄은 다음과 같습니다.

byte[] base64String = Base64.decode(encodedString); 
byte[] plainBytes = new String(base64String).getBytes("UTF-8"); 
byte[] cipherData = cipher.doFinal(plainBytes); 

System.out.println(cipherData); 
return cipherData.toString(); 

.NET에서 암호화하는 데 사용한 단계의 순서를 반대로해야합니다. 먼저 암호화 된 문자열을 Base64로 해독하여 암호 바이트를 가져와야합니다. 당신이 그랬지 만 그 결과를 base64String으로 오인했습니다. 이 결과는 cipherData이라고해야합니다. 둘째, cipherData를 해독하여 일반 텍스트를 가져와야합니다. 셋째, 두 번째 인수에 대한 Charset을 사용하여 두 개의 arg 문자열 생성자를 사용하여 plainbytes에서 문자열을 만들어야합니다. 여기에 코드가 어떻게 보이게 될지, 아니면 가까이에 있어야합니다.

byte[] cipherData = Base64.decode(encodedString); 
byte[] plainBytes = cipher.doFinal(cipherData); 

return new String(plainBytes, "UTF-8"); 

마지막으로 Java의 모든 개체에는 toString() 메서드가 있지만 항상 원하는 것은 아닙니다. 배열의 경우 toString() 메서드는 해당 배열에 대한 객체 ID 표현을 반환하며 메모리 주소에 해당하는 JVM을 반환합니다.

편집 :

난 당신이 또한 해독 코드에서 잘못된 키를 사용하고 있는지 놓쳤다. 귀하가 RSA 공개 키를 사용하고 있지만 대신 RSA 개인 키를 사용해야합니다.

+0

개인 키를 사용하고 있지만이를 생성하기 위해 공용 모듈을 생성하는 데 사용하는 동일한 모듈러스 및 지수를 사용하고 있습니다 ... 그게 정확하지 않습니까? – Reixons

+0

내 첫 번째 문제 코드는 또한 개인 키를 생성하기 위해 지수를 사용하고 있었고 키의 "D"부분을 사용해야했습니다. 이제는 작동합니다. 모두 감사합니다 !! – Reixons

+0

나는 아주 비슷한 것을하고 있지만 해독 결과로, 널 (null) 입력 버퍼를 얻었습니다 : java.lang.IllegalArgumentException : 코드의 어딘가에 널 (Null) 입력 버퍼가 있습니다. 개인 키를 인쇄했는데 다음과 같은 것 같습니다 : Sun RSA 개인 키 1024 비트 모듈러스 : 17117003084657245951324093201042962541622648817557411074899862199275295356525279994079227 개인 지수 : 9947330202515462552673473204475943107757877312593094815482420010684084799297468584099129255754448231415771883606131 58181121242481 너무 길기 때문에 나는 그 부분을 꺼 냈습니다. 왜 이런 일이 일어나는 지 알고 싶습니다. – c0d3Junk13

1

:

는 여기에 현재 비 작업 코드를 추가합니다. RSA 키는 x509 인증서입니다.

자바 RSA/AES :

// symmetric algorithm for data encryption 
final String ALGORITHM = "AES"; 
// Padding for symmetric algorithm 
final String PADDING_MODE = "/CBC/PKCS5Padding"; 
// character encoding 
final String CHAR_ENCODING = "UTF-8"; 
// provider for the crypto 
final String CRYPTO_PROVIDER = "Entrust"; 
// RSA algorithm used to encrypt symmetric key 
final String RSA_ALGORITHM = "RSA/ECB/PKCS1Padding"; 
// symmetric key size (128, 192, 256) if using 192+ you must have the Java 
// Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 
// installed 
int AES_KEY_SIZE = 256; 

private byte[] encryptWithRSA(byte[] aesKey, X509Certificate cert) 
     throws NoSuchAlgorithmException, NoSuchPaddingException, 
     InvalidKeyException, IllegalBlockSizeException, BadPaddingException { 
    // get the public key from the encryption certificate to encrypt with 
    PublicKey pubKey = cert.getPublicKey(); 

    // get an instance of the RSA Cipher 
    Cipher rsaCipher = Cipher.getInstance(RSA_ALGORITHM); 

    // set the cipher to use the public key 
    rsaCipher.init(Cipher.ENCRYPT_MODE, pubKey); 

    // encrypt the aesKey 
    return rsaCipher.doFinal(aesKey); 
} 

private AESEncryptedContents encryptWithAes(byte[] dataToEncrypt) 
     throws NoSuchAlgorithmException, NoSuchPaddingException, 
     InvalidKeyException, IllegalBlockSizeException, 
     BadPaddingException, NoSuchProviderException { 
    // get the symmetric key generator 
    KeyGenerator keyGen = KeyGenerator.getInstance(ALGORITHM); 
    keyGen.init(AES_KEY_SIZE); // set the key size 

    // generate the key 
    SecretKey skey = keyGen.generateKey(); 

    // convert to binary 
    byte[] rawAesKey = skey.getEncoded(); 

    // initialize the secret key with the appropriate algorithm 
    SecretKeySpec skeySpec = new SecretKeySpec(rawAesKey, ALGORITHM); 

    // get an instance of the symmetric cipher 
    Cipher aesCipher = Cipher.getInstance(ALGORITHM + PADDING_MODE, 
      CRYPTO_PROVIDER); 

    // set it to encrypt mode, with the generated key 
    aesCipher.init(Cipher.ENCRYPT_MODE, skeySpec); 

    // get the initialization vector being used (to be returned) 
    byte[] aesIV = aesCipher.getIV(); 

    // encrypt the data 
    byte[] encryptedData = aesCipher.doFinal(dataToEncrypt); 

    // package the aes key, IV, and encrypted data and return them 
    return new AESEncryptedContents(rawAesKey, aesIV, encryptedData); 
} 

private byte[] decryptWithAES(byte[] aesKey, byte[] aesIV, 
     byte[] encryptedData) throws NoSuchAlgorithmException, 
     NoSuchPaddingException, InvalidKeyException, 
     InvalidAlgorithmParameterException, IllegalBlockSizeException, 
     BadPaddingException, UnsupportedEncodingException, 
     NoSuchProviderException { 
    // initialize the secret key with the appropriate algorithm 
    SecretKeySpec skeySpec = new SecretKeySpec(aesKey, ALGORITHM); 

    // get an instance of the symmetric cipher 
    Cipher aesCipher = Cipher.getInstance(ALGORITHM + PADDING_MODE, 
      CRYPTO_PROVIDER); 

    // set it to decrypt mode with the AES key, and IV 
    aesCipher.init(Cipher.DECRYPT_MODE, skeySpec, 
      new IvParameterSpec(aesIV)); 

    // decrypt and return the data 
    byte[] decryptedData = aesCipher.doFinal(encryptedData); 

    return decryptedData; 
} 

private byte[] decryptWithRSA(byte[] encryptedAesKey, PrivateKey privKey) 
     throws IllegalBlockSizeException, BadPaddingException, 
     InvalidKeyException, NoSuchAlgorithmException, 
     NoSuchPaddingException, NoSuchProviderException { 
    // get an instance of the RSA Cipher 
    Cipher rsaCipher = Cipher.getInstance(RSA_ALGORITHM, CRYPTO_PROVIDER); 

    // set the cipher to use the public key 
    rsaCipher.init(Cipher.DECRYPT_MODE, privKey); 

    // encrypt the aesKey 
    return rsaCipher.doFinal(encryptedAesKey); 
} 

C# 닷넷 : 이해가되지 않는 자바 해독 코드의

public byte[] encryptData(byte[] data, out byte[] encryptedAesKey, out byte[] aesIV) { 
    if (data == null) 
     throw new ArgumentNullException("data"); 

    byte[] encryptedData; // data to return 

    // begin AES key generation 
    RijndaelManaged aesAlg = new RijndaelManaged(); 
    aesAlg.KeySize = AES_KEY_SIZE; 
    aesAlg.GenerateKey(); 
    aesAlg.GenerateIV(); 
    aesAlg.Mode = CipherMode.CBC; 
    aesAlg.Padding = PaddingMode.PKCS7; 

    // aes Key to be encrypted 
    byte[] aesKey = aesAlg.Key; 

    // aes IV that is passed back by reference 
    aesIV = aesAlg.IV; 

    //get a new RSA crypto service provider to encrypt the AES key with the certificates public key 
    using (RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider()) 
    { 
     //add the certificates public key to the RSA crypto provider 
     rsaCSP.FromXmlString(encryptionCertificate.PublicKey.Key.ToXmlString(false)); 

     //encrypt AES key with RSA Public key 
     //passed back by reference 
     encryptedAesKey = rsaCSP.Encrypt(aesKey, false); 

     //get an aes encryptor instance 
     ICryptoTransform aesEncryptor = aesAlg.CreateEncryptor(); 

     encryptedData = encryptWithAes(aesEncryptor, data); 
    } 

    if (encryptedData == null) 
     throw new CryptographicException(
       "Fatal error while encrypting with AES"); 

    return encryptedData; 
} 

private byte[] encryptWithAes(ICryptoTransform aesEncryptor, byte[] data) { 
    MemoryStream memStream = null; // stream to write encrypted data to 
    CryptoStream cryptoStream = null; // crypto stream to encrypted data 

    try { 
     memStream = new MemoryStream(); 

     // initiate crypto stream telling it to write the encrypted data to 
     // the memory stream 
     cryptoStream = new CryptoStream(memStream, aesEncryptor, 
       CryptoStreamMode.Write); 

     // write the data to the memory stream 
     cryptoStream.Write(data, 0, data.Length); 
    } catch (Exception ee) { 
     // rethrow 
     throw new Exception("Error while encrypting with AES: ", ee); 
    } finally { 
     // close 'em 
     if (cryptoStream != null) 
      cryptoStream.Close(); 
     if (memStream != null) 
      memStream.Close(); 
    } 

    // return the encrypted data 
    return memStream.ToArray(); 
} 
+0

고마워요 피티! 나는 코드를 시도 할 것이다 ... 나는 그것이 작동하고 byte [] 문자열 변환에 어떤 문제도주지 않기를 바란다. 나는 그것을 적응 시키려고 노력할 것이다 (나는 certs 또는 AES를 사용하지 않는다). 그리고 나는 그것을 시도하자마자 sth를 게시 할 것이다. 다시 한 번 감사드립니다! – Reixons

+0

@ Reixons, 문제 없어요, 제가 도울 수 있다면 알려주세요. 무엇을 암호화 하시겠습니까? RSA 키 길이보다 길면 AES + RSA를 사용해야합니다. –

+0

음, 코드를 테스트 한 결과 몇 가지 문제점이 있습니다. 내가 얻을 : javax.crypto.BadPaddingException : 데이터가 0으로 시작해야합니다 나는 그것을 2h에서 더 나은 설명하려고합니다. 나는 지금 그것을 할 충분한 명성이 없다! : – Reixons

0

내 게시물의 첫 번째 답변과 관련하여 어제 게시 할 수없는 답변은 다음과 같습니다.

음, 코드를 테스트 한 결과 몇 가지 문제점이 있습니다. 나는 그것이 완전히 필요하지 않으면 아무것도 바꾸지 않으려 고 노력했다. 먼저 나는 여기에서 오류가 발생합니다 :

Cipher rsaCipher = Cipher.getInstance(RSA_ALGORITHM, CRYPTO_PROVIDER); 

은 "러스트"암호 제공자가 인식되지는 ... 그래서 난 그냥 첫 번째 매개 변수를 떠났다. 그런 다음이 오류가 발생합니다.

.NET에서 작성된 WebService를 통해 항상 바이트 배열을 반환합니다. 어쩌면 번역에 어떤 문제가있을 수 있습니다. Base64 숫자를 사용해야한다는 것을 알고 있고 AES를 사용하지 않는다면 RSA 키로 제한된 128 바이트 크기로 문자열을 분해해야합니다. 나는 여전히 Java에서 암호화하고 .NET에서 해독 할 수 있지만 그 반대는 아닌 이유를 알기 위해이 문제를 해결하기 위해 노력하고 있습니다.

다시 도움 주셔서 감사합니다.