2017-02-15 60 views
1

我已经写了两个函数来解密和加密C#和Javascript中的消息,但我也需要它在Java中,我无法让它与以前的相同。在Java中重现加密方法

JS加密方法:

this.aesEncrypt = function (encryptedMessage) { 
    var key = CryptoJS.enc.Utf8.parse("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); 
    var initialVector = CryptoJS.enc.Utf8.parse("xxxxxxxxxxxxxxxx"); 
    var encryptedText = CryptoJS.AES.encrypt(encryptedMessage, key, 
    { 
     iv: initialVector, 
     mode: CryptoJS.mode.CBC, 
     padding: CryptoJS.pad.Pkcs7 
    }); 
    return encryptedText.toString().hexEncode(); 
} 
String.prototype.hexEncode = function() { 
    var hex, i; 

    var result = ""; 
    for (i = 0; i < this.length; i++) { 
     hex = this.charCodeAt(i).toString(16); 
     result += ("0" + hex).slice(-2); 
    } 

    return result; 
} 

C#解密方法:

private static string AesDecrypt(string encryptedMessage) 
{ 
    try 
    { 
     var temp = FromHex(encryptedMessage); 
     var encryptedBytes = Convert.FromBase64String(Encoding.ASCII.GetString(temp)); 
     var aes = new AesCryptoServiceProvider 
     { 
      BlockSize = 128, 
      KeySize = 256, 
      Mode = CipherMode.CBC, 
      Padding = PaddingMode.PKCS7, 
      Key = Encoding.UTF8.GetBytes("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"), 
      IV = Encoding.UTF8.GetBytes("xxxxxxxxxxxxxxxx") 
     }; 
     var crypto = aes.CreateDecryptor(aes.Key, aes.IV); 
     var secret = crypto.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length); 
     crypto.Dispose(); 
     return Encoding.ASCII.GetString(secret); 
    } 
    catch (Exception) 
    { 
     return null; 
    } 
} 

public static byte[] FromHex(string hex) 
{ 
    hex = hex.Replace("-", ""); 
    var raw = new byte[hex.Length/2]; 
    for (var i = 0; i < raw.Length; i++) 
    { 
     raw[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16); 
    } 
    return raw; 
} 

的Java加密方法:加密后

public static String toHex(String arg) { 
    return String.format("%x", new BigInteger(1, arg.getBytes())); 
} 
public static String AesEncrypt(String encryptedMessage){ 
    try { 
     IvParameterSpec initialVector = new IvParameterSpec("xxxxxxxxxxxxxxxx".getBytes("UTF-8")); 
     SecretKeySpec secretKeySpec = new SecretKeySpec("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx".getBytes("UTF-8"), "AES"); 

     Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
     cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, initialVector); 

     byte[] encrypted = cipher.doFinal(encryptedMessage.getBytes()); 
     StringBuilder encryptedSb = new StringBuilder(encrypted.length); 
     for (byte i : encrypted){ 
      encryptedSb.append(i); 
     } 
     return toHex(encryptedSb.toString()); 
    } catch (Exception ex) { 
     ex.printStackTrace(); 
     return null; 
    } 
} 

爪哇返回80六数字和JS返回48六-digits。 AFAIK Java PKCS5填充与C#PKCS7填充相同。

我也曾尝试使用使用
http://commons.apache.org/proper/commons-codec/download_codec.cgi
结果base64编码,但它仍然不是这个。

public static String AesEncrypt(String encryptedMessage){ 
    try { 
     IvParameterSpec initialVector = new IvParameterSpec("xxxxxxxxxxxxxxxx".getBytes("UTF-8")); 
     SecretKeySpec secretKeySpec = new SecretKeySpec("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx".getBytes("UTF-8"), "AES"); 

     Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
     cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, initialVector); 

     byte[] encrypted = cipher.doFinal(encryptedMessage.getBytes()); 

     byte[] base64 = Base64.encodeBase64(encrypted); 

     StringBuilder encryptedSb = new StringBuilder(base64.length); 
     for (byte i : base64){ 
      encryptedSb.append(i); 
     } 
     return toHex(encryptedSb.toString()); 
    } catch (Exception ex) { 
     ex.printStackTrace(); 
     return null; 
    } 
} 
+0

这只是为了好玩吗?你基本上不想实现你自己的加密算法。 – Michael

+0

您正在使用哪个Java提供程序? – Keith

+2

@Michael,我没有实现我自己的算法。我正在使用AES CBC和PKCS7 Padding –

回答

-1

我忘了编码到Base64。我在最近的问题编辑中几乎在那里。我只是忘记了Base64.encodeBase64String这实际上没有工作,但我看了Base64类中的这个函数的实现,我发现如何更明确地做到这一点。

public static String AesEncrypt(String encryptedMessage){ 
    try { 
     IvParameterSpec initialVector = new IvParameterSpec("xxxxxxxxxxxxxxxx".getBytes("UTF-8")); 
     SecretKeySpec secretKeySpec = new SecretKeySpec("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx".getBytes("UTF-8"), "AES"); 

     Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
     cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, initialVector); 

     byte[] encrypted = cipher.doFinal(encryptedMessage.getBytes()); 
     String base64 = StringUtils.newStringUtf8(Base64.encodeBase64(encrypted, false)); 

     return toHex(base64); 
    } catch (Exception ex) { 
     ex.printStackTrace(); 
     return null; 
    } 
} 
+0

看到我的帖子下面。使用'DatatypeConverter'。它有静态单行程序来转换编码。 – Keith

+0

我无法导入'javax.xml.bind.DatatypeConverter' –

+0

复制/粘贴其代码。它很简单。 – Keith

2

不管任何其他参数的,AES上16字节的块进行操作。 Java AES中的PCKS#5填充将解析为PCKS#7。使用PCKS#7,您正在填充到块边界;即填充到最接近的16个字节。

您的UTF-8输入“ABC”是3个字节。 16字节将需要(16-3)= 13字节的填充。因此,密文将是16个字节,或32个十六进制字符。

说了这么多,我认为您的StringBuildertoHex()逻辑之间的编码转换有些问题。尝试使用DatatypeConverter.printHexBinary(byte[] val)byte[] encrypted转换回十六进制。

+0

你是对的关于编码:) –