2016-04-13 20 views
3

私はプロジェクト関連の目的のために文字列を暗号化する必要があり、ベンダー別に以下のコードを与えました。C#RSACryptoServiceProviderコードをJavaに翻訳する

public static string EncryptString(string StringToEncrypt) 
{ 
    RSACryptoServiceProvider provider = new RSACryptoServiceProvider(); 
    string xmlString = "<RSAKeyValue><Modulus>qqoWhMwGrrEBRr92VYud3j+iIEm7652Fs20HvNckH3tRDJIL465TLy7Cil8VYxJre69zwny1aUAPYItybg5pSbSORmP+hMp6Jhs+mg3qRPvHfNIl23zynb4kAi4Mx/yEkGwsa6L946lZKY8f9UjDkLJY7yXevMML1LT+h/a0a38=</Modulus><Exponent>AQAB</Exponent><P>20PwC7nSsfrfA9pzwSOnRYdbhOYivFSuERxvXHvNjCll5XdmFYYp1d2evXcXbyj3E1k8azce1avQ9njH85NMNQ==</P><Q>x0G0lWcQ13NDhEcWbA7R2W5LPUmRqcjQXo8qFIaHk7LZ7ps9fAk/kOxaCR6hvfczgut1xSpXv6rnQ5IGvxaHYw==</Q><DP>lyybF2qSEvYVxvFZt8MeM/jkJ5gIQPLdZJzHRutwx39PastMjfCHbZW0OYsflBuZZjSzTHSfhNBGbXjO22gmNQ==</DP><DQ>NJVLYa4MTL83Tx4vdZ7HlFi99FOI5ESBcKLZWQdTmg+14XkIVcZfBxDIheWWi3pEFsWqk7ij5Ynlc/iCXUVFvw==</DQ><InverseQ>X5Aw9YSQLSfTSXEykTt7QZe6SUA0QwGph3mUae6A2SaSTmIZTcmSUsJwhL7PLNZKbMKSWXfWoemj0EVUpZbZ3Q==</InverseQ><D>jQL4lEUYCGNMUK6GEezIRgiB5vfFg8ql3DjsOcXxnOmBcEeD913kcYnLSBWEUFW55Xp0xW/RXOOHURgnNnRF3Ty5UR73jPN3/8QgMSxV8OXFo3+QvX+KHNHzf2cjKQDVObJTKxHsHKy+L2qjfULA4e+1cSDNn5zIln2ov51Ou3E=</D></RSAKeyValue>"; 
    provider.FromXmlString(xmlString); 
    return Convert.ToBase64String(provider.Encrypt(Encoding.ASCII.GetBytes(StringToEncrypt), false)); 
} 

しかし、私はJAVAに変更または翻訳する必要があります。私は同じ目的のために以下の方法を書きました。

public static String EncryptString(String strToBeEncrypted) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, UnsupportedEncodingException, IllegalBlockSizeException, BadPaddingException 
{ 
    String modulusString = "qqoWhMwGrrEBRr92VYud3j+iIEm7652Fs20HvNckH3tRDJIL465TLy7Cil8VYxJre69zwny1aUAPYItybg5pSbSORmP+hMp6Jhs+mg3qRPvHfNIl23zynb4kAi4Mx/yEkGwsa6L946lZKY8f9UjDkLJY7yXevMML1LT+h/a0a38="; 
    String publicExponentString = "AQAB"; 
    byte[] modulusBytes = Base64.decodeBase64(modulusString); 
    byte[] exponentBytes = Base64.decodeBase64(publicExponentString); 
    BigInteger modulus = new BigInteger(1, modulusBytes); 
    BigInteger publicExponent = new BigInteger(1, exponentBytes); 
    RSAPublicKeySpec rsaPubKey = new RSAPublicKeySpec(modulus, publicExponent); 
    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 = strToBeEncrypted.getBytes("US-ASCII"); 
    byte[] cipherData = cipher.doFinal(plainBytes); 
    String encryptedStringBase64 = Base64.encodeBase64String(cipherData); 

    return encryptedStringBase64; 
} 

しかし、サンプルの結果は一致しません。

文字列は "4111111111111111" で、暗号化された結果は次のようになります。

PfU31ai9dSwWX4Im19TlikfO9JetkJbUE + btuvpBuNHTnnfrt4XdM4PmGA19z8rF + lPUC/kcOEXciUSxFrAPyuRJHifIDqWFbbJvPhatbf269BXUiAW31UBX3X5bBOqNWjh4LDitYY0BtarlTU4xzOFyb7vLpLJe9aHGWhzs6q0 =

しかし、Javaコードから結果が

Cxp5AIzTHEkrU6YWwYo5yYvpED2qg9ICです/ 0ct + tRgDZi9fJb8LAk + E1l9ljEt7MFQ2KB/exo 4NYwijnBKYPeLStXyfVO1Bj6S76zMeKygAlCtDukq1UhJaJKaCXY94wi9Kel09VTmj + VByIYvAGUFqZGaK1CyLnd8QXMcdcWi3sA =

+2

C#コードとJavaコードを再度実行するとどうなりますか?暗号文は変わるのですか?そうであれば、ランダム化されたパディングが使用され(重要)、一方で暗号化し、他方で復号化して互換性をチェックする必要があります。 –

+0

@ArtjomBありがとうございます。ベンダーの解読コードとの互換性を確認したところ、うまくいきました。 @ArtjomB。 – RahulMuk07

+0

暗号化にはランダム化されたパディング*を使用する必要があります。暗号化は非決定論的でなければなりません。そうでないと、同じ平文に対して同じ暗号文が得られます(対称ECBモード暗号化と同じです)。テキストブックRSAだけが決定論的であり、すべての種類または理由で非常に安全ではありません。署名生成は決定論的であるかもしれません。あなたは答えを投稿できますか? –

答えて

1

すべての暗号化アルゴリズムは、意味的なセキュリティを提供するために、ランダム化される必要があります。さもなければ、攻撃者はあなたが暗号文を観察することによって同じメッセージを再び送ったことに気付くでしょう。対称暗号では、この特性はランダムIVによって達成される。 RSAでは、ランダム化されたパディング(PKCS#1 v1.5タイプ2およびPKCS#1 v2.x OAEPがランダム化されています)によって実現されます。

パディングがランダム化されているかどうかは、同じキーとプレーンテキストで再度暗号化を実行し、前の暗号文と比較することで確認できます。暗号文が実行の間にC#またはJavaのいずれかで変化する場合、暗号文を調べるだけで、暗号化が互換性があるかどうかを知ることができません。

これを確認する適切な方法は、ある言語で何かを暗号化し、もう一方の言語で復号化することです。完全な互換性を得るには、逆もまた試してみるべきです。 にfalseが第2パラメータとして渡され、PKCS#1 v1.5パディングを使用し、Cipher.getInstance("RSA/ECB/PKCS1PADDING")が同じパディングを要求するため、コードを見ると、どちらも同等と見なされます。入力/出力エンコーディングも同じように見えます。したがって、このコードは同等です。それはBleichenbacherの攻撃(reference)に対して脆弱であるため、


PKCS#1 v1.5のパディングは、今日では使用すべきではありません。暗号化にはOAEPを使用し、署名にはPSSを使用する必要があります。 C#とJavaはどちらもOAEPをサポートしていますが、使用されるデフォルトのハッシュ関数(ハッシュとMGF1)には違いがあります。

+0

こんにちは、私はquesitonで同じシナリオに直面しています。ランダムパディングが使用されている場合、データベースからパスワードを解読しないで、ユーザーが入力したパスワードがデータベースのパスワードと同じであるかどうかを確認するにはどうすればよいですか?私はパスワードの復号化を聞いたので、良い習慣ではありません。暗号化された値が同じかどうかだけを確認します。しかし、ここで私はそれをどうやって行うことができないのか分かりません。唯一の方法は、dbからパスワードを解読するようです。 – nanospeck

+0

@nanospeckユーザーのパスワードを決して暗号化しないでください。代わりに、ハッシュを使用する必要があります。強力なものはPBKDF2、bcrypt、scrypt、Argon2です。ハッシュ関数は単方向関数なので、ハッシュを "解読"することはできません。ユーザーを認証するには、データベースに格納されているハッシュと比較するために、ハッシュ関数を使用してパスワードを再度実行します。詳細:[パスワードを安全にハッシュする方法](http://security.stackexchange.com/q/211/45523)RSAは間違いなく間違ったツールです。 –

+0

あなたの言葉は本当に話題になってくれました。残念ながら、RSACryptoServiceProviderを使用して.NETに既に実装されているプロジェクトをJavaに移植しているため、パスワードの暗号化を再実装することはできません。 – nanospeck

関連する問題