AES暗号化アルゴリズムとSHA1PRNGハッシュを使用して文字列を暗号化および復号化するAndroidデバイスで使用されている次のJavaコードがあります。AndroidデバイスでC#で記述された.NETWCFサービスを呼び出すようにします。私は、Javaコードと同様の方法で暗号化および復号化できる、C#で同等のものを見つけようとあらゆる場所を検索してきましたが、まったく同じ方法を見つけることができませんでした。両方の言語のEncrypt()メソッドは次のとおりです。
Java:
public static String encrypt(String seed, String cleartext) throws Exception
{
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(seed);
kgen.init(128, sr); // 192 and 256 bits may not be available
SecretKey skey = kgen.generateKey();
byte[] rawKey = skey.getEncoded();
SecretKeySpec skeySpec = new SecretKeySpec(rawKey, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(cleartext.getBytes());
return toHex(encrypted);
}
これに似たものをC#で作成しましたが、これもAESとSHA1を使用しています。
C#:
public static string Encrypt(string seed, string cleartext)
{
var objAesCrypto = new AesManaged();
var objHashSha1 = new SHA1Managed();
var byteHash = objHashSha1.ComputeHash(Encoding.ASCII.GetBytes(seed));
var truncatedHash = new byte[16];
Array.Copy(byteHash, truncatedHash, truncatedHash.Length);
objAesCrypto.Key = truncatedHash;
objAesCrypto.Mode = CipherMode.ECB;
var byteBuff = Encoding.ASCII.GetBytes(cleartext);
return Convert.ToBase64String(objAesCrypto.CreateEncryptor().TransformFinalBlock(byteBuff, 0, byteBuff.Length));
}
ただし、これにはいくつかの問題があります。ご覧のとおり、C#バージョンのSHA1(SHA1Managed)を使用すると、16ではなく20バイトのハッシュが返されます。AESアルゴリズムに渡す唯一の方法は、最初にハッシュを16バイトに切り捨てることです。
2番目の問題は、どちらもそれぞれの環境で正常に機能しますが、Javaから暗号化された文字列をシードと一緒に渡そうとすると、C#コードで正しく復号化できないことです。どちらの場合も、暗号化された文字列は同じようには見えず、長さも異なります。Java側からの典型的な暗号化された文字列は、次のようになります: F7E8758A2E65518FB49C53BC707288FC
(32文字の長さ)。C#側からの同じ正確なシードを持つ同じ正確な暗号化文字列は次のようになります: 3VysgnYgNi9OJBxL2FP+rQ==
(24文字の長さ)。
私がC#でハッシュを切り捨てているという事実と関係があると確信していますが、それは2つの暗号化された文字列がそれほど大きく異なる理由を説明していません。(私が気付いたもう1つの興味深い点は、C#側で使用する文字列とシードに関係なく、常に24文字の長さで、2つの等号で終わることです。これはなぜですか?)
だから、私の質問は、同じシード値を使用して両方の環境が互いの暗号化された文字列を復号化できるようにするにはどうすればよいですか?C#側でJava側とは異なるアルゴリズムを使用する必要があるかどうかは関係ありません。必要なのは、Javaで暗号化された文字列を読み取れるようにするためのC#コードだけです。