2013-10-17 21 views
9

Tôi cần mã hóa chuỗi chắc chắn từ phía máy khách (JavaScript) và giải mã từ phía máy chủ (Java), vì vậy tôi đã tìm thấy CryptoJS và tôi viết mã với cùng các thông số/cấu hình của mi Mã Java nhưng đầu ra luôn khác nhau, bạn có bất kỳ ý tưởng hay điều gì xảy ra không?Mã hoá đầu ra khác nhau cả Mã hóa và Mã Java

Tôi sử dụng CBC với NoPadding

CryptoJS

http://jsfiddle.net/Soldier/gCHAG/

<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/aes.js"> 
</script> 
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/components/pad-nopadding-min.js"></script> 
<script> 

    function padString(source) { 
     var paddingChar = ' '; 
     var size = 16; 
     var x = source.length % size; 
     var padLength = size - x; 

     for (var i = 0; i < padLength; i++) source += paddingChar; 

     return source; 
    } 

    var key = CryptoJS.enc.Hex.parse('abcdef'); 
    var iv = CryptoJS.enc.Hex.parse('fedcba'); 
    var message = "soldier"; 
    var padMsg = padString(message); 

    var encrypted = CryptoJS.AES.encrypt(padMsg, key, { iv: iv, padding: CryptoJS.pad.NoPadding, mode: CryptoJS.mode.CBC}); 

    console.log("Encrypted: "+encrypted); 
    console.log("Encrypted text: "+encrypted.ciphertext); 

</script> 

Java Mã

import java.security.Key; 
import javax.crypto.Cipher; 
import javax.crypto.spec.IvParameterSpec; 
import javax.crypto.spec.SecretKeySpec; 
import sun.misc.*; 

public class AesCipher { 

    private static final String algorithm = "AES/CBC/NoPadding"; 

    private static final byte[] keyValue = new byte[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; 
    private static final byte[] ivValue = new byte[] { 'f', 'e', 'd', 'c', 'b', 'a', '9', '8', '7', '6', '5', '4', '3', '2', '1', '0' }; 

    private static final IvParameterSpec ivspec = new IvParameterSpec(ivValue); 
    private static final SecretKeySpec keyspec = new SecretKeySpec(keyValue, "AES"); 

    final protected static char[] hexArray = "ABCDEF".toCharArray(); 

    public static String encrypt(String Data) throws Exception { 
     Cipher c = Cipher.getInstance(algorithm); 
     c.init(Cipher.ENCRYPT_MODE, keyspec, ivspec); 
     byte[] encVal = c.doFinal(Data.getBytes()); 
     String encryptedValue = new BASE64Encoder().encode(encVal); 
     return encryptedValue; 
    } 

    public static String decrypt(String encryptedData) throws Exception { 
     Cipher c = Cipher.getInstance(algorithm); 
     c.init(Cipher.DECRYPT_MODE, keyspec, ivspec); 
     byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedData); 
     byte[] decValue = c.doFinal(decordedValue); 
     String decryptedValue = new String(decValue); 
     return decryptedValue; 
    } 

    public static String bytesToHex(byte[] bytes) { 
     char[] hexChars = new char[bytes.length * 2]; 
     int v; 
     for (int j = 0; j < bytes.length; j++) { 
      v = bytes[j] & 0xFF; 
      hexChars[j * 2] = hexArray[v >>> 4]; 
      hexChars[j * 2 + 1] = hexArray[v & 0x0F]; 
     } 
     return new String(hexChars); 
    } 

    private static String padString(String source) { 
     char paddingChar = ' '; 
     int size = 16; 
     int x = source.length() % size; 
     int padLength = size - x; 

     for (int i = 0; i < padLength; i++) 
     { 
      source += paddingChar; 
     } 
     return source; 
     } 

    public static void main(String[] args) throws Exception { 

     String password = "soldier"; 
     String passwordEnc = AesCipher.encrypt(padString(password)); 
     String passwordDec = AesCipher.decrypt(passwordEnc); 

     System.out.println("Plain Text : " + password); 
     System.out.println("Encrypted Text : " + passwordEnc); 
     System.out.println("Decrypted Text : " + passwordDec); 
    } 

} 

gốc chuỗi:

soldier 

Output từ CryptoJS:

Encrypted: VNzZNKJTqfRbM7zO/M4cDQ== 
Encrypted Hex: 54dcd934a253a9f45b33bccefcce1c0d 

Output từ Mã Java:

Encrypted: j6dSmg2lfjY2RpN91GNgNw== 
Encrypted Hex: 6a3664536d67326c666a593252704e3931474e674e773d3d 

Chuỗi base64 mã hóa có cùng chiều dài nhưng không phải là hex. Nếu tôi đặt kết quả đầu ra của CryptoJS trong Mã Java, giải mã không chính xác.

Kính trọng,

Trả lời

7

Vấn đề ở đây là đầu vào chính của bạn không phù hợp.

  • CryptoJS.enc.Hex.parse('abcdef') lần đọc đầu vào như một loạt các byte thể hiện dưới dạng giá trị hai chữ số hex: 01, 23, 45 vv

  • mảng Java của bạn xác định byte giá trị sử dụng các giá trị ký tự mã hóa của các ký tự. Vì vậy, chuỗi các byte (trong hex) là: 30 (thập phân 48, mã ASCII cho '0'), sau đó 31 (thập phân 49, mã ASCII cho '1') vv

Bạn có thể làm cho phù hợp với JavaScript đến việc thực hiện bằng cách sử dụng Java CryptoJS.enc.Latin1.parse mà sẽ đọc trong các giá trị nhân vật cá nhân và sử dụng chúng như các giá trị byte: http://jsfiddle.net/gCHAG/1/ (điều này tạo ra cùng j6dSm... đầu ra)

Tuy nhiên, có thể bạn muốn mỗi chữ số để được byte riêng của mình. Để làm điều đó, bạn cần phải thay đổi cả hai triển khai.

Java:

// use hex literals, not characters 
byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }; 
// array values: 0x00, 0x01, 0x02, etc 

JavaScript: ví dụ

// remember each bytes is two digits wide 
CryptoJS.enc.Hex.parse('000102030405060708090a0b0c0d0e0f') 
// array values: 0x00, 0x01, 0x02, etc 
+0

Hoạt động tốt, cảm ơn rất nhiều :) – SoldierCorp

1

Nhân vật '0' là không giống như giá trị hex 0. CryptoJS quan trọng là có khả năng nhất khác với phím Java bởi vì bạn đang instantiating họ loại đối tượng như nhau. In ra các phím/IV bằng cả hai ngôn ngữ sau khi tạo và so sánh chúng.

EDIT: Điều đó nói rằng, điều này có thể sẽ được chuyển sang StackOverflow, vì các câu hỏi về thư viện mật mã cụ thể không phải là chủ đề ở đây.

+0

Yup, xin lỗi . Đang chỉnh sửa ngay bây giờ. – pg1989

0

Rất hữu ích SoldierCorp, cảm ơn bạn!

Vài điều cần cải thiện ví dụ của bạn:

  • Phương pháp padString không hỗ trợ UTF8 và thay vì sửa chữa phương pháp này cho phép xóa nó và sử dụng một đệm chuẩn

trong javascript thay thế trên

padding: CryptoJS.pad.Pkcs7 

bằng java thay thế trên

algorithm = "AES/CBC/PKCS5Padding" 
  • Tạo chìa khóa từ bất kỳ cụm từ chuỗi (ví IV có thể giống nhau)

trong javascript thay thế trên

var key = CryptoJS.MD5("Secret Passphrase"); 

trong java thay thế trên

byte[] keyValue = org.apache.commons.codec.digest.DigestUtils.md5("Secret Passphrase"); 
+0

Tôi không nghĩ rằng đó là một ý tưởng tốt để sử dụng MD5 cho dẫn xuất quan trọng. Tốt hơn là sử dụng PBKDF2. Điều tốt là CryptoJS và Java đều hỗ trợ PBKDF2 một cách tự nhiên. –

Các vấn đề liên quan