2010-10-17 83 views
20

Tôi có chương trình sau để mã hóa dữ liệu.Mã hóa và giải mã bằng mã hóa AES và Base64

import java.security.Key; 

import javax.crypto.Cipher; 
import javax.crypto.spec.SecretKeySpec; 

import org.apache.commons.codec.binary.Base64; 

public class Test { 

    private static final String ALGORITHM = "AES"; 
    private static final byte[] keyValue = "ADBSJHJS12547896".getBytes(); 

    public static void main(String args[]) throws Exception { 
     String encriptValue = encrypt("dude5"); 
     decrypt(encriptValue); 

    } 

    /** 
    * @param args 
    * @throws Exception 
    */ 

    public static String encrypt(String valueToEnc) throws Exception { 

     Key key = generateKey(); 
     Cipher c = Cipher.getInstance(ALGORITHM); 
     c.init(Cipher.ENCRYPT_MODE, key); 

     System.out.println("valueToEnc.getBytes().length "+valueToEnc.getBytes().length); 
     byte[] encValue = c.doFinal(valueToEnc.getBytes()); 
     System.out.println("encValue length" + encValue.length); 
     byte[] encryptedByteValue = new Base64().encode(encValue); 
     String encryptedValue = encryptedByteValue.toString(); 
     System.out.println("encryptedValue " + encryptedValue); 

     return encryptedValue; 
    } 

    public static String decrypt(String encryptedValue) throws Exception { 
     Key key = generateKey(); 
     Cipher c = Cipher.getInstance(ALGORITHM); 
     c.init(Cipher.DECRYPT_MODE, key); 

     byte[] enctVal = c.doFinal(encryptedValue.getBytes()); 
     System.out.println("enctVal length " + enctVal.length); 

     byte[] decordedValue = new Base64().decode(enctVal); 

     return decordedValue.toString(); 
    } 

    private static Key generateKey() throws Exception { 
     Key key = new SecretKeySpec(keyValue, ALGORITHM); 
     return key; 
    } 

} 

Ở đây tôi nhận được những điều sau đây có ngoại lệ?

valueToEnc.getBytes().length 5 
encValue length16 
encryptedValue [[email protected] 
Exception in thread "main" javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher 
    at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..) 
    at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..) 

Một số người có thể giải thích cho tôi nguyên nhân không? Tại sao chỉ nói khi giải mã độ dài đó là 16. Không chuyển đổi thành 16 giống như mã hóa bằng phương thức doFinal.

Và ngoại lệ cho biết "cách giải mã mà không có mật mã độn?"

+0

Bạn đã đúng trừ 2 điểm. Tôi đã đề cập trong một câu trả lời khác .. –

Trả lời

44

Đơn hàng của bạn cho mã hóa:getBytes, mã hóa, mã hóa, toString
Đơn hàng của bạn cho giải mã:getBytes, giải mã, giải mã, toString

Hai vấn đề:

  1. Khi ai đó đã đề cập bạn nên đảo ngược thứ tự các hoạt động cho d ecryption. Bạn không làm điều đó.
  2. Mã hóa
  3. cung cấp cho bạn 16 byte, mã hóa 24 byte, nhưng toString cung cấp 106 byte. Một cái gì đó để làm với ký tự không hợp lệ chiếm không gian bổ sung.

Lưu ý: Ngoài ra, bạn không cần phải gọi generateKey() hai lần.

Khắc phục sự cố số 1 bằng cách sử dụng thứ tự ngược lại để giải mã. Thứ tự chính xác:getBytes, giải mã, giải mã, toString
Khắc phục sự cố # 2 bằng cách thay thế xxx.toString() bằng new String(xxx). Làm điều này trong cả hai chức năng mã hóa và giải mã.

giải mã của bạn sẽ trông như thế này:

c.init(Cipher.DECRYPT_MODE, key) 
val decodedValue = new Base64().decode(encryptedValue.getBytes()) 
val decryptedVal = c.doFinal(decodedValue) 
return new String(decryptedVal) 

này sẽ cho bạn trở lại "dude5"

+1

ở đầu câu trả lời của bạn, bạn cung cấp thứ tự giải mã như: getBytes, giải mã, giải mã, toString. Sau đó, bạn đưa ra thứ tự chính xác như: getBytes, giải mã, giải mã, toString. Tôi tin rằng thứ tự thứ hai là chính xác. – Magnus

+2

Magnus, ở trên cùng của câu trả lời của tôi, khi tôi đề cập đến "Đặt hàng của bạn ...", đó là thứ tự mà OP đang thực hiện chuỗi. "Của bạn" đề cập đến OP. Đó không phải là thứ tự của tôi. –

+2

Điều quan trọng cần lưu ý là người ta phải luôn sử dụng Bộ ký tự cụ thể khi tạo Chuỗi từ byte [] và ngược lại: ví dụ: 'chuỗi mới (byte," UTF-8 ")' và 'string.getBytes (" UTF-8 ")'. Điều này đảm bảo rằng nếu mã hóa và giải mã được thực thi trên các hệ thống khác nhau với các bảng mã hệ thống khác nhau, điều này sẽ không dẫn đến thất bại. –

0

Về cơ bản, có sự bất đối xứng giữa chức năng mã hóa và chức năng giải mã của bạn. Khi bạn mã hóa bạn thực hiện mã hóa AES và sau đó mã hóa base64, khi bạn giải mã, trước tiên bạn không hoàn tác bước mã hóa base64.

Tôi nghĩ rằng có điều gì đó sai với mã hóa base64 của bạn cũng như [ không được xuất hiện trong chuỗi được mã hóa base64.

Nhìn vào tài liệu cho org.apache.commons.codec.binary.Base64 bạn sẽ có thể làm điều này trên mã hóa:

String encryptedValue = Base64.encodeBase64String(encValue); 

và điều này trên decode:

byte[] encValue = Base64.decodeBase64(encryptedValue); 
+0

thers là không có phương pháp như encodeBase64String charles – Harshana

+0

@Harshana: Đây là gì, sau đó? http://commons.apache.org/codec/apidocs/org/apache/commons/codec/binary/Base64.html#encodeBase64String%28byte[]%29 –

3

Dòng

String encryptedValue = encryptedByteValue.toString(); 

là vấn đề. Loại encryptedByteValue là byte [] và gọi toString trên nó không phải là những gì bạn muốn làm ở đó. Thay vào đó hãy thử

String encryptedValue = Base64.getEncoder().encodeToString(encValue); 

Sau đó, sử dụng Base64.decodeBase64(encryptedValue) để giải mã. Bạn phải làm điều đó trước khi cố giải mã. Bạn phải hoàn tác các thao tác theo thứ tự ngược lại của phương thức mã hóa.

+0

chỉ cần thêm vào đó để trả về Chuỗi từ phương thức..cũng trong Base64 không có phương thức như vậy encodeToString – Harshana

+0

Về toString, gọi phương thức đó trên một mảng là hầu như không bao giờ bạn muốn làm gì. Nó trả về địa chỉ trong bộ nhớ của đối tượng, không phải là biểu diễn String hữu ích. Về Base64, bạn có đang sử dụng nó không? http://commons.apache.org/codec/apidocs/org/apache/commons/codec/binary/Base64.html Xem phương thức tại đây: http://commons.apache.org/codec/apidocs/org/apache/commons/codec/binary/Base64.html#encodeToString%28byte[]%29 – laz

+0

ive đặt commons-codec-1.2 và cũng thử 1,3 jar nhưng có vẻ như phương pháp không hiển thị biết .. – Harshana

2

Bạn nhận phiên bản codec apache ở đâu có encodeToString hoặc encodeBase64String?

Tôi đã tải xuống 1,5 từ trang web apache và trong khi tài liệu nói rằng trong các tài liệu này, chúng không hiển thị khi bạn hoàn thành mã và tạo phương thức không xác định khi bạn cung cấp.

tôi đã có thể làm:

byte raw[] = md.digest(); //step 4 
byte hashBytes[] = Base64.encodeBase64(raw); //step 5 
StringBuffer buffer = new StringBuffer(); 
for(int i=0; i<hashBytes.length; i++) 
    buffer.append(hashBytes[i]); 
return buffer.toString(); //step 6 

Và rồi chuỗi mà tôi thu được là rất dài, nhưng nó giải mã một cách chính xác.

Tôi không nghĩ đây là cách "đúng" để thực hiện, nhưng không thể tìm thấy các phương pháp mà tài liệu nói ở đó.

0

Tôi có thay thế dòng trong ví dụ:

String encryptedValue = encryptedByteValue.toString(); 

với tới một:

String encryptedValue = new String(encryptedByteValue); 

Tất cả đều hoạt động tốt!

+1

Tôi nghiêm túc nghi ngờ điều này sửa lỗi ngoại lệ đệm; nhiều khả năng là bạn đang chạy một JVM khác. –

0

Đó là ổn, bạn chỉ cần thiết để

1) Sử dụng new String thay vì toString() kể từ toString() không trả lại những gì bạn cần ở đây (trong cả hai trường hợp, mã hóa và giải mã)

2) bạn cần phải giải mã đầu tiên kể từ khi giá trị được mã hóa trong base64.

Tôi đã xem qua chủ đề này nhưng phải mất một lúc để tìm ra điểm thực tế..Tôi đang đăng mã của mình cho phần còn lại của những người gặp phải vấn đề này.

public abstract class EncryptionDecryption { 
static byte[] key = "[email protected]#[email protected]#$%^&**&^%".getBytes(); 
final static String algorithm="AES"; 

public static String encrypt(String data){ 

    byte[] dataToSend = data.getBytes(); 
    Cipher c = null; 
    try { 
     c = Cipher.getInstance(algorithm); 
    } catch (NoSuchAlgorithmException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (NoSuchPaddingException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
    SecretKeySpec k = new SecretKeySpec(key, algorithm); 
    try { 
     c.init(Cipher.ENCRYPT_MODE, k); 
    } catch (InvalidKeyException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
    byte[] encryptedData = "".getBytes(); 
    try { 
     encryptedData = c.doFinal(dataToSend); 
    } catch (IllegalBlockSizeException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (BadPaddingException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
    byte[] encryptedByteValue = new Base64().encode(encryptedData); 
    return new String(encryptedByteValue);//.toString(); 
} 

public static String decrypt(String data){ 

    byte[] encryptedData = new Base64().decode(data); 
    Cipher c = null; 
    try { 
     c = Cipher.getInstance(algorithm); 
    } catch (NoSuchAlgorithmException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (NoSuchPaddingException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
    SecretKeySpec k = 
      new SecretKeySpec(key, algorithm); 
    try { 
     c.init(Cipher.DECRYPT_MODE, k); 
    } catch (InvalidKeyException e1) { 
     // TODO Auto-generated catch block 
     e1.printStackTrace(); 
    } 
    byte[] decrypted = null; 
    try { 
     decrypted = c.doFinal(encryptedData); 
    } catch (IllegalBlockSizeException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (BadPaddingException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
    return new String(decrypted); 
} 

public static void main(String[] args){ 
    String password=EncryptionDecryption.encrypt("password123"); 
    System.out.println(password); 
    System.out.println(EncryptionDecryption.decrypt(password)); 
} 
} 
Các vấn đề liên quan