Java相当于C#AES加密

时间:2015-11-27 09:34:43

标签: java encryption encoding aes

我在C#中有以下代码。它使用AES对称算法对字节数组进行编码。我需要编写相当于此代码的Java。

class Program
{
    static void Main(string[] args)
    {
        string a = "ABCDEFGHIJKLMNOP";
        byte[] bytes = Encoding.ASCII.GetBytes(a);
        byte[] cipher = encode(bytes, "1111111122222222111111112222222211111111222222221111111122222222", "66666666555555556666666655555555");
    }

    private static byte[] encode(byte[] toEncrypt, string sKey, string sIV)
    {
        byte[] IV = new byte[16];
        byte[] key = new byte[32];
        byte[] array = new byte[toEncrypt.Length];
        string s;

        for (int i = 0; i < IV.Length; ++i)
        {
            s = sIV.Substring(i * 2, 2);
            IV[i] = Convert.ToByte(s, 16);
        }

        for (int i = 0; i < key.Length; ++i)
        {
            s = sKey.Substring(i * 2, 2);
            key[i] = Convert.ToByte(s, 16);
        }

        MemoryStream filecrypt = new MemoryStream(array);

        AesManaged encrypt = new AesManaged();
        encrypt.Mode = CipherMode.CBC;
        encrypt.Padding = PaddingMode.None;
        encrypt.BlockSize = 128;
        encrypt.KeySize = 256;

        CryptoStream cs = new CryptoStream(filecrypt, encrypt.CreateEncryptor(key, IV), CryptoStreamMode.Write);
        cs.Write(toEncrypt, 0, toEncrypt.Length);
        cs.Close();

        return array;
    }
}

这是我尝试用Java编写的。代码看起来很好,但输出不同,一定是错误的。

public class Main {

    public static void main(String [] args) {
        byte [] code = encode("ABCDEFGHIJKLMNOP".getBytes(), "1111111122222222111111112222222211111111222222221111111122222222", "66666666555555556666666655555555");
    }

    private static byte[] toByteArray(String s) {
        int len = s.length();
        byte[] data = new byte[len / 2];
        int a;
        int b;
        for (int i = 0; i < len; i += 2) {
            a = (Character.digit(s.charAt(i), 16) << 4);
            b = Character.digit(s.charAt(i+1), 16);
            int n = (Character.digit(s.charAt(i), 16) << 4)
                    + Character.digit(s.charAt(i+1), 16);
                data[i / 2] = (byte) (n);
        }
        return data;
    }

    private static byte[] encode(byte[] toEncrypt, String skey, String siv)
    {
        byte[] key = toByteArray(skey);
        byte[] iv = toByteArray(siv);

        byte[] array = new byte[toEncrypt.length];

        Cipher cipher;

        try {
            cipher = Cipher.getInstance("AES/CBC/NoPadding");
            cipher.init(Cipher.ENCRYPT_MODE,  new SecretKeySpec(key, "AES"), new IvParameterSpec(iv));
            array = cipher.doFinal(array);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return array;
    }
}

非常感谢任何线索和想法。

4 个答案:

答案 0 :(得分:4)

我不太了解C#,但总的来说,您希望多个连续加密结果不同。这就是为AES算法指定初始IV的原因。加密代码可能如下所示:

  public String encrypt( String stringToEncrypt, IvParameterSpec ivSpec ) {
    if ( stringToEncrypt == null ) {
      return null;
    }
    try {
      Cipher cipher = Cipher.getInstance( "AES/CBC/PKCS5Padding");
      SecretKeySpec keySpec = new SecretKeySpec( key, "AES" );
      cipher.init( Cipher.ENCRYPT_MODE, keySpec, ivSpec );
      byte[] data = cipher.doFinal( stringToEncrypt.getBytes( "UTF-8" ) );
      return String.format( "%s:%s", Base64.encode( ivSpec.getIV() ), Base64.encode( data ) );
    } catch ( Exception e ) {
      throw new RuntimeException( "Unable to encrypt the string", e );
    }
  }

你的密钥和你的IV应该使用SecureRandom生成,因为这提供了java中最好的熵:

byte[] iv = new byte[32];
random.nextBytes( iv );
byte[] key = new byte[32];
random.nextBytes( key );

此外,您可能希望之后计算HMAC - 此处java也支持多种解决方案。通过检查接收方的HMAC,可以防止填充oracle攻击。

为了比较不同的加密结果,我会将它们与base64编码进行比较。

注意:可以将密码保存在密文旁边 - 它可以防止预计算攻击。

答案 1 :(得分:2)

您出于某种原因正在初始化git-rebase,但在加密之前,您永远不会将byte[] array = new byte[toEncrypt.length];的内容写入其中。您可以使用toEncrypt,但只使用

会更容易
System.arraycopy(toEncrypt, 0, array, 0, array.length);

答案 2 :(得分:0)

就个人而言,如果您的目标是简单地使用Java加密AES,则不应将代码基于C#类。当然它们可能相似,但Java已经有了强大的库。

除此之外,我希望我的加密书可以在这里向您解释,但不幸的是,我现在能做的最好的事情只是为您提供其他人尝试过的好例子:

我希望这些链接可以帮助您实现目标。

此外,关于您的特定c#代码,我无法看到您在Java中指定以下代码的位置:

encrypt.BlockSize = 128;
encrypt.KeySize = 256;

在第二个教程中,我建议您有一个示例,指定密钥大小。我希望我能帮忙!

答案 3 :(得分:0)

public String notify(String message, String encryptionKey) {
    Security.addProvider(new BouncyCastleProvider());
    // System.out.println(message);
    byte[] key = Base64.decode(encryptionKey);
    SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
    byte[] data = Base64.decode(message);
    String decryptedString = "";
    try {
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
        cipher.init(Cipher.DECRYPT_MODE, skeySpec);
        byte[] decrypted = cipher.doFinal(data);
        decryptedString = new String(decrypted);
    } catch (Exception e) {
        e.printStackTrace();
    }
    System.out.println(decryptedString);
    return decryptedString;
}

此代码应解密加密所需填充的加密邮件 - 默认128位,但您需要提供加密密钥。 但是这是我的相同代码的C#版本

 void DecryptMessage(string message)
    {
        var deserializedMessage = JsonConvert.DeserializeObject<List<string>>(message.ToString());
        byte[] decodedEncryptionKey = Convert.FromBase64String(encryptkey);
        byte[] data = Convert.FromBase64String(deserializedMessage[0]);
        byte[] iv = new byte[16];
        AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
        aes.BlockSize = 128;
        aes.KeySize = 128;
        aes.Mode = CipherMode.ECB;
        aes.Padding = PaddingMode.PKCS7;

        using (ICryptoTransform decrypt = aes.CreateDecryptor(decodedEncryptionKey, iv))
        {
            byte[] dest = decrypt.TransformFinalBlock(data, 0, data.Length);
            decrypt.Dispose();
            Console.WriteLine(Encoding.UTF8.GetString(dest));
        }
    }