我在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;
}
}
非常感谢任何线索和想法。
答案 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));
}
}