2016-08-31 14 views
2

私はJavaで同等のものを作成しようとしているC#のキーと塩を使ってStringをエンコードされたStringに変換するメソッドを使用しました。私は、すべての無駄とウェブ上の多くの異なる解決策を試みたJavaへのC#暗号化メソッド

public static string Encrypt<T>(string Value, string Key, string Salt) where T : SymmetricAlgorithm, new() 
    { 
     DeriveBytes deriveBytes = new Rfc2898DeriveBytes(Key, Encoding.Unicode.GetBytes(Salt)); 

     SymmetricAlgorithm algorithm = new T(); 
     byte[] keyBytes = deriveBytes.GetBytes(algorithm.KeySize >> 3); 
     byte[] ivBytes = deriveBytes.GetBytes(algorithm.BlockSize >> 3); 

     ICryptoTransform transform = algorithm.CreateEncryptor(keyBytes, ivBytes); 

     using (MemoryStream buffer = new MemoryStream()) 
     { 
      using (CryptoStream stream = new CryptoStream(buffer, transform, CryptoStreamMode.Write)) 
      { 
       using (StreamWriter writer = new StreamWriter(stream, Encoding.Unicode)) 
       { 
        writer.Write(Value); 
       } 
      } 

      return Convert.ToBase64String(buffer.ToArray()); 
     } 
    } 

次のよう

C#の方法があります。私もサンプルがあります

value("YourId|YourFacId")key("6JxI1HOSg7KQj4fJ1Xb3L1T6AVdLZLBAPFSqOjh2UoA=")

salt("FPSJxiSMpAavjKqyGvVe1A==")

これらのすべての上記の方法に送信されますが、バックの戻り文字列で来る:
"Y5w4A3pDZwTcq+FGyqUMO/mZSr6hSst8qiac9zDbfso9FQQbdTDsKnkKDT7SHl4y"

私の問題と一致するものはまだ見つかりませんでしたので、ここで助けを探しています。どんなリードも感謝します。ありがとう。

他の質問へのリンクは、私がまだ見ていないことは何も示していませんでした。私の例で扱うパスワードはありません。 は、ここでは、この時の私の多くの失敗した試みの一つである:使用

アルゴリズムは256ビットAesManaged次のとおりです。

private String encrypt(String user) throws Exception 
{ 
    Cipher deCipher; 
    Cipher enCipher; 
    SecretKeySpec key; 
    IvParameterSpec ivSpec; 
    String plainKey = "6JxI1HOSg7KQj4fJ1Xb3L1T6AVdLZLBAPFSqOjh2UoA="; 
    String salt = "FPSJxiSMpAavjKqyGvVe1A=="; 
    String result = ""; 
    ivSpec = new IvParameterSpec(salt.getBytes()); 
    key = new SecretKeySpec(plainkey.getBytes(), "AES"); 
    enCipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
    byte[] input = convertToByteArray(user); 
    enCipher.init(Cipher.ENCRYPT_MODE, key, ivSpec); 

    return new String(enCipher.doFinal(input).toString()); 
} 
+0

はここにJavaで暗号化を行う方法について、正当な(おそらく重複した)質問があるようですが、現在、これは、コード変換の問題のように見える、と人々反射的にdownvoteとクローズコードの翻訳の質問 –

+0

'新しいT()'は何ですか? –

+0

これは、デフォルトの反復回数でPBKDF2から派生したキーとIVを使用した単純なCBC暗号化です。それは何度も議論されました。 –

答えて

3

ありがとう:私はあなたを伝えることができる最後のことは、暗号化されたバイト配列(ベース64エンコーディング前の最後のステップ)は次のようになりますメッセージの値をエンコードするときには使用しますが、ソルトの値をエンコードするときには使用しません。同等のJavaコードは次のようになります。

import java.io.UnsupportedEncodingException; 
import java.nio.charset.StandardCharsets; 
import java.security.GeneralSecurityException; 
import java.security.spec.KeySpec; 
import java.util.Arrays; 
import java.util.Base64; 

import javax.crypto.Cipher; 
import javax.crypto.SecretKey; 
import javax.crypto.SecretKeyFactory; 
import javax.crypto.spec.IvParameterSpec; 
import javax.crypto.spec.PBEKeySpec; 
import javax.crypto.spec.SecretKeySpec; 

class SO39257791 
{ 

    private static final int KEY_LEN = 256/8, BLOCK_LEN = 16, ITERATIONS = 1000; 

    public static void main(String... argv) 
    throws Exception 
    { 
    String value = "YourId|YourFacId"; 
    String key = "6JxI1HOSg7KQj4fJ1Xb3L1T6AVdLZLBAPFSqOjh2UoA="; 
    String salt = "FPSJxiSMpAavjKqyGvVe1A=="; 
    String good = "Y5w4A3pDZwTcq+FGyqUMO/mZSr6hSst8qiac9zDbfso9FQQbdTDsKnkKDT7SHl4y"; 

    String output = encrypt(value, key, salt); 
    if (output.equals(good)) 
     System.out.println("strings are equal"); 
    else 
     System.out.println("strings are NOT equal!"); 
    } 

    static final String encrypt(String value, String key, String salt) 
    throws GeneralSecurityException, UnsupportedEncodingException 
    { 
    /* Derive the key, given password and salt. */ 
    byte[] s = salt.getBytes(StandardCharsets.UTF_16LE); 
    int dkLen = (KEY_LEN + BLOCK_LEN) * 8; 
    KeySpec spec = new PBEKeySpec(key.toCharArray(), s, ITERATIONS, dkLen); 
    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); 
    byte[] dk = factory.generateSecret(spec).getEncoded(); 
    SecretKey secret = new SecretKeySpec(Arrays.copyOfRange(dk, 0, KEY_LEN), "AES"); 
    byte[] iv = Arrays.copyOfRange(dk, KEY_LEN, KEY_LEN + BLOCK_LEN); 

    /* Encrypt the message. */ 
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
    cipher.init(Cipher.ENCRYPT_MODE, secret, new IvParameterSpec(iv)); 
    byte[] plaintext = value.getBytes("UnicodeLittle"); /* Use Byte Order Mark */ 
    byte[] ciphertext = cipher.doFinal(plaintext); 

    return Base64.getEncoder().encodeToString(ciphertext); 
    } 

} 
+3

くそー! UnicodeLittle対UnicodeLittleUnmarked - それは意味です:) –

+0

それは素晴らしい動作します!あなたと@Stefan Zobelのおかげで大きな助けになりました。私は自分でこれを考え出すことはなかったでしょう。 –

3

は私だけあなたが軌道に乗るためにいくつかの部分的な情報を与えることができます。モードはCBCで、パディングは

あなたに与えられたサンプル値256が

static void Main(string[] args) 
{ 
    string key = "6JxI1HOSg7KQj4fJ1Xb3L1T6AVdLZLBAPFSqOjh2UoA="; 
    string salt = "FPSJxiSMpAavjKqyGvVe1A=="; 
    string value = "YourId|YourFacId"; 

    string result = Encrypt<AesManaged>(value, key, salt); 
    Console.WriteLine(result); 
    string expected = "Y5w4A3pDZwTcq+FGyqUMO/mZSr6hSst8qiac9zDbfso9FQQbdTDsKnkKDT7SHl4y"; 
    if (expected.Equals(result)) 
    { 
     Console.WriteLine("strings are equal"); 
    } 
    else 
    { 
     Console.WriteLine("strings are NOT equal!"); 
    } 
} 

keysaltは無地あるこの小さなテストプログラムで正しいことを示すことができる= PKCS7とキーサイズです文字列(base-64はエンコードされていません)。彼らにとって、バイトを取得するには、Javaであなたは私に次のようになります

byte[] saltBytes = salt.getBytes("UnicodeLittleUnmarked"); 
    byte[] keyBytes = key.getBytes("UTF-8"); 

PBKDF2は、SHA1ダイジェスト1000回の反復を使用しています(私ははBouncyCastleのPKCS5S2ParametersGeneratorでこれをチェックする)

final int iterations = 1000; 
    PKCS5S2ParametersGenerator pbkdf = new PKCS5S2ParametersGenerator(new SHA1Digest()); 
    pbkdf.init(keyBytes, saltBytes, iterations); 
    final int keySize = 32 * 8; 
    final int ivSize = 16 * 8; 
    CipherParameters cp = pbkdf.generateDerivedParameters(keySize, ivSize); 

を使用する必要がありますivBytesとkeyBytes

// Java ivBytes 
// [-33, 102, -108, 66, -46, 89, 122, 102, -63, -15, -92, 66, -88, -29, 67, -59] 

// Java keyBytes: 
// [-127, 125, -40, -123, 60, -70, 16, -6, -15, -116, 127, 93, 46, 80, 26, 31, -36, 47, -120, -37, 57, 21, -94, 44, 98, -119, -109, 48, -71, 15, -36, 80] 

これらは、私はC#のコードで何を得るために署名した等価物である:

// C# ivBytes: 
// [223, 102, 148, 66, 210, 89, 122, 102, 193, 241, 164, 66, 168, 227, 67, 197] 

// C# keyBytes: 
// [129, 125, 216, 133, 60, 186, 16, 250, 241, 140, 127, 93, 46, 80, 26, 31, 220, 47, 136, 219, 57, 21, 162, 44, 98, 137, 147, 48, 185, 15, 220, 80] 

私はC#のコードを読んで、値のバイトもここからUTF-16リトルエンディアン

byte[] valueBytes = value.getBytes("UnicodeLittleUnmarked"); 

として取得する必要があり、私はさらに進行することはできません。私はC#のコードがバイトオーダーマークが含まれていることを見つけStefana little fiddling,

// C# crypted: 
// [99, 156, 56, 3, 122, 67, 103, 4, 220, 171, 225, 70, 202, 165, 12, 59, 249, 153, 74, 190, 161, 74, 203, 124, 170, 38, 156, 247, 48, 219, 126, 202, 61, 21, 4, 27, 117, 48, 236, 42, 121, 10, 13, 62, 210, 30, 94, 50] 

// or signed: 
// [99, -100, 56, 3, 122, 67, 103, 4, -36, -85, -31, 70, -54, -91, 12, 59, -7, -103, 74, -66, -95, 74, -53, 124, -86, 38, -100, -9, 48, -37, 126, -54, 61, 21, 4, 27, 117, 48, -20, 42, 121, 10, 13, 62, -46, 30, 94, 50] 
+0

@zaphまあ、C#のテストプログラムは明らかにBase64のデコードを行わずに正しい出力を生成します。そして、ivBytes/keyBytes byte []配列は正しい長さを持ちます。 –

+0

この全体的な質問は恐ろしい混乱です。 – zaph

+0

@zaphあなたは何について話しているのですか? –