2015-05-29 52 views
1

我想了解爲什麼使用Java或Node.js加密它時加密數據發生了變化,我需要修改node.js代碼以使其返回與我在Java上完全相同的加密數據。 (請注意,我不能修改Java代碼)爲什麼node.js的加密模塊會給出與Java的Cipher類進行AES加密不同的結果?

Node.js的執行情況:

var crypto = require('crypto'); 

console.log("\n\n============"); 
var cKey = new Buffer("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "utf-8"); 
var cIv = new Buffer("1111111111111111", "utf-8"); 
var cData = "x"; 
console.log(cKey); 
console.log(cIv); 
console.log("UTF-8 Data: " + cData); 

var cipher = crypto.createCipheriv("aes-256-cbc", cKey, cIv); 
var cipherText = cipher.update(cData, 'utf8', 'hex') + cipher.final('hex'); 

console.log("Our data: " + cipherText); 

前面的代碼將打印以下結果:

<Buffer 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41> 
<Buffer 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31> 
UTF-8 Data: x 
Our data: 0eddfe1857248c7057904455d189cf31 

Java實現:

byte[] key = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA".getBytes(); 
byte[] data = "x".getBytes(); 
byte[] iv = "1111111111111111".getBytes(); 
Cipher cipher = Cipher.getInstance("AES"); 
IvParameterSpec ivspec = new IvParameterSpec(iv); 
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), ivspec); 
byte[] result = cipher.doFinal(data); 
_print(result); 

這個代碼將打印:

17b0ccd594229baa6dabd5e850e07fdf 

請注意,我比較了數據,IV和密鑰和那些字節是完全一樣的。

如何修改節點的代碼片段,使其返回java的相同字節?

+2

我認爲在java'AES'的意思是'aes-128-cbc'。我猜密鑰大小在獲取密碼文本中很重要。 – Kishore

+0

什麼是AesSymmetricKey?這門課來自哪裏,它有什麼作用? if和initializationVector有什麼區別?爲什麼Java代碼調用EncryptionService.encryptAesData,然後調用cipher.doFinal?是有原因還是隻是冗餘? – wallenborn

+0

對不起,我忘了刪除它,它不是這段代碼的一部分。 –

回答

3

您需要使用相同的操作模式。您的java代碼將密碼字符串指定爲「AES」。這是不完全限定的,所以你的默認JCE提供者將選擇它自己的默認值「AES」,這是「AES/ECB/PKCS5Padding」(你的情況),因爲它是最基本的一個,但也是不安全的模式。

您需要在node.js中使用相同的操作模式。你需要改變的只有兩件事情是IV尺寸(ECB不使用IV!)和密碼字符串:

var cIv = new Buffer(0); 
var cipher = crypto.createCipheriv("aes-256-ecb", cKey, cIv); 

請注意,ECB模式本身不是語義安全。此外,密文未經過驗證,所以您應該使用HMAC-SHA256的加密 - 然後MAC方案或者GCM或EAX等經過身份驗證的模式。

+0

'Cipher.getInstance(「AES」)''和'Cipher.getInstance(「AES/ECB/PKCS5padding」)'是一樣的。 –

+0

@ rakeb.void是的,對於大多數JCE提供者(包括Sun JCE)來說都是如此,但它並不一定適用於所有人。 JCE提供者可以決定默認爲'Cipher.getInstance(「AES/CBC/PKCS5padding」)'全零IV或類似的東西。這就是爲什麼使用完全合格的密碼字符串總是一個好主意。 –

0

你node.js的代碼看起來像它做什麼,它聲稱在做,如下面的單元測試成功:

@Test 
public void testAes() throws InvalidKeyException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException { 
    byte[] key = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA".getBytes(); 
    byte[] data = "x".getBytes(); 
    byte[] iv = "1111111111111111".getBytes(); 
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING"); 
    IvParameterSpec ivspec = new IvParameterSpec(iv); 
    cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), ivspec); 
    byte[] result = cipher.doFinal(data); 
    assertEquals("0eddfe1857248c7057904455d189cf31", DatatypeConverter.printHexBinary(result).toLowerCase()); 
} 

我懷疑你的Java代碼沒有做它聲稱在做。