Tôi đang sử dụng khóa rsa để mã hóa chuỗi dài mà tôi sẽ gửi đến máy chủ của mình (sẽ mã hóa nó bằng khóa công khai của máy chủ và khóa riêng của tôi) ném một ngoại lệ như javax.crypto.IllegalBlockSizeException: Data must not be longer than 256 bytes
Tôi cảm thấy rằng tôi đã không hiểu công việc của rsa đúng cho đến bây giờ (sử dụng các thư viện sẵn có là nguyên nhân cho việc này).
Có thể một số người vui lòng giải thích lý do ngoại lệ này bị ném. Nó không phải là có thể gửi chuỗi dài mã hóa?nhận được một IllegalBlockSizeException: Dữ liệu không được dài hơn 256 byte khi sử dụng rsa
Trả lời
Thuật toán RSA chỉ có thể mã hóa dữ liệu có chiều dài tối đa byte chiều dài khóa RSA trong bit chia với tám trừ mười một đệm byte, tức là số byte tối đa = chiều dài then chốt trong bit/8-11 .
Vì vậy, về cơ bản bạn chia độ dài khóa bằng 8 -11 (nếu bạn có đệm). Ví dụ: nếu bạn có khóa 2048bit, bạn có thể mã hóa 2048/8 = 256 byte (- 11 byte nếu bạn có đệm). Vì vậy, hoặc sử dụng một khóa lớn hơn hoặc bạn mã hóa dữ liệu bằng một khóa đối xứng và mã hóa khóa đó bằng rsa (đó là phương pháp được khuyến nghị).
Điều đó sẽ yêu cầu bạn phải:
- tạo ra một đối xứng chính
- Mã hóa dữ liệu với các đối xứng chính
- Mã hóa khóa đối xứng với rsa
- gửi chìa khóa mã hóa và dữ liệu
- Giải mã khóa đối xứng được mã hóa bằng rsa
- giải mã dữ liệu bằng khóa đối xứng
- done :)
Tại sao có hạn chế như vậy, bạn có thể mã hóa dữ liệu tối đa một độ dài nhất định? – Ashwin
Giới hạn 'chiều dài khóa bằng bit/8 - 11' chỉ hợp lệ khi' PKCS1Padding' được sử dụng. Ví dụ, với giới hạn 'NoPadding' sẽ là' chiều dài khóa bằng bit/8'. – divanov
Cả hai PKCS # 1v1.5 padding và không có padding là không an toàn. Sử dụng đệm OAEP (làm giảm kích thước khối nhiều hơn 11 byte) – CodesInChaos
Bạn không nên sử dụng RSA trực tiếp trên dữ liệu bí mật của mình. Bạn chỉ nên sử dụng RSA trên giả ngẫu nhiên hoặc hoàn toàn ngẫu nhiên dữ liệu, chẳng hạn như khóa phiên hoặc mã xác thực thư.
Bạn đã gặp sự cố ở 256 byte - đó là vì bạn có thể đang làm việc với 2048 khóa bit. Các khóa có thể mã hóa bất kỳ số nguyên nào trong phạm vi 0
thành 2^2048 - 1
vào cùng một phạm vi và điều đó có nghĩa là dữ liệu của bạn phải từ 256 byte trở xuống.
Nếu bạn dự định mã hóa nhiều hơn, hãy sử dụng một mã hóa RSA để mã hóa khóa phiên cho thuật toán đối xứng và sử dụng để mã hóa dữ liệu của bạn.
Tại sao có hạn chế như vậy, bạn có thể mã hóa dữ liệu tối đa một độ dài nhất định? – Ashwin
Bởi vì RSA được thực hiện trên một _finite [ring] (http://en.wikipedia.org/wiki/Ring_ (toán học)) _, các số duy nhất tồn tại là các số nguyên trong phạm vi '[0, 2^2048- 1] ', bao gồm. Bất kỳ thư nào dài hơn 2048 bit đại diện cho một số nằm ngoài phạm vi này và phải được mã hóa theo hai khối hoặc - nếu bạn muốn an toàn - toàn bộ thông điệp phải được mã hóa trong khóa phiên. RSA được triển khai trong thế giới thực phải bảo vệ chống lại [nhiều cuộc tấn công] (http://en.wikipedia.org/wiki/RSA_ (thuật toán) #Attacks_against_plain_RSA), và không bao giờ làm việc trên văn bản thô "thô" là một phần quan trọng trong việc sử dụng RSA một cách an toàn. – sarnold
Để tiếp tục từ câu trả lời của John Snow ở trên, tôi đã tạo một thư viện ngẫu nhiên-đối xứng đơn giản mà bạn có thể sử dụng để mã hóa bất kỳ dữ liệu độ dài nào bằng khóa riêng.
Bạn có thể tìm thấy các thư viện tại GitHub - random-symmetric-crypto
final RandomSymmetricCipher cipher = new RandomSymmetricCipher();
// Encrypt the data and the random symmetric key.
final CryptoPacket cryptoPacket = cipher.encrypt(inputData, PRIVATE_KEY_BASE64);
// Convert the CryptoPacket into a Base64 String that can be readily reconstituted at the other end.
final CryptoPacketConverter cryptoPacketConverter = new CryptoPacketConverter();
final String base64EncryptedData = cryptoPacketConverter.convert(cryptoPacket);
System.out.println("Base64EncryptedData=" + base64EncryptedData);
// Decrypt the Base64 encoded (and encrypted) String.
final byte[] outputData = cipher.decrypt(base64EncryptedData, PUBLIC_KEY_BASE64);
Tôi không thể tìm thấy nơi bạn chỉ định chế độ đệm để sử dụng. Bạn nên chỉ định rõ ràng padding OAEP, vì các paddings phổ biến khác như PKCS # 1v1.5 hoặc không có padding ở tất cả đều không an toàn. – CodesInChaos
Vui lòng chấp nhận yêu cầu kéo. Bạn có một URL để hỗ trợ không có phần đệm không an toàn không? – William
Boneh đã viết một tổng quan tốt về [cuộc tấn công chống lại RSA] (http://crypto.stanford.edu/~dabo/papers/RSA-survey.pdf). Crypto.se cũng có rất nhiều câu hỏi về sách giáo khoa RSA (http://crypto.stackexchange.com/search?q=textbook+rsa). Tôi không thể tìm thấy MAC trong phần đối xứng của mã của bạn. Điều này có nghĩa là bạn sẽ dễ bị tấn công chủ động, chẳng hạn như những bí mật đệm. Lớp đệm PKCS # 1v1.5 cũ và vẫn phổ biến cũng dễ bị tấn công chủ động (trừ khi bạn làm việc xung quanh điểm yếu * thực sự * cẩn thận), cụ thể là đòn tấn công của Bleichenbacher. – CodesInChaos
bạn cần chia dữ liệu theo PublicKey
int keyLength = publicKey.getModulus().bitLength()/16;
String[] datas = splitString(data, keyLength - 11);
String mi = ""//the data after encrypted;
for (String s : datas) {
mi += bcd2Str(cipher.doFinal(s.getBytes()));
}
return mi;
public static String bcd2Str(byte[] bytes) {
char temp[] = new char[bytes.length * 2], val;
for (int i = 0; i < bytes.length; i++) {
val = (char) (((bytes[i] & 0xf0) >> 4) & 0x0f);
temp[i * 2] = (char) (val > 9 ? val + 'A' - 10 : val + '0');
val = (char) (bytes[i] & 0x0f);
temp[i * 2 + 1] = (char) (val > 9 ? val + 'A' - 10 : val + '0');
}
return new String(temp);
}
Chỉ vì bạn có thể làm điều gì đó không có nghĩa là bạn nên làm. Điều cần thiết là mã hóa lai nơi dữ liệu được mã hóa bằng thuật toán đối xứng như AES sử dụng khóa ngẫu nhiên và khóa được mã hóa bằng RSA. – zaph
Lưu ý: 1. "dữ liệu" là số nhiều, "mốc" là dạng số ít. 2. Phương thức 'bcd2Str' thực sự thực hiện mã hóa thập lục phân [0-9A-Z]. 3. Có thể không cần phải mã hóa đầu ra nhị phân bằng mã hóa RSA và nếu mã hóa là cần thiết, trong khi hệ thập lục phân là OK, trường hợp thông thường là sử dụng mã hóa Base64, nó nhỏ gọn hơn. – zaph
Dựa trên @ John Tuyết trả lời, tôi đã làm một ví dụ
Tạo khóa đối xứng (AES với 128 bit)
KeyGenerator generator = KeyGenerator.getInstance("AES"); generator.init(128); // The AES key size in number of bits SecretKey secKey = generator.generateKey();
Mã hóa văn bản đơn giản sử dụng AES
String plainText = "Please encrypt me urgently..." Cipher aesCipher = Cipher.getInstance("AES"); aesCipher.init(Cipher.ENCRYPT_MODE, secKey); byte[] byteCipherText = aesCipher.doFinal(plainText.getBytes());
Encrypt phím sử dụng RSA công cộng quan trọng
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); kpg.initialize(2048); KeyPair keyPair = kpg.generateKeyPair(); PublicKey puKey = keyPair.getPublic(); PrivateKey prKey = keyPair.getPrivate(); Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.PUBLIC_KEY, puKey); byte[] encryptedKey = cipher.doFinal(byteCipherText);
Gửi mã hóa dữ liệu (byteCipherText) + mã hóa AES Key (encryptedKey)
Ở phía máy khách, giải mã khóa đối xứng bằng khóa riêng RSA
cipher.init(Cipher.PRIVATE_KEY, prKey); byte[] decryptedKey = cipher.doFinal(encryptedKey);
Giải mã các mật mã bằng cách sử dụng giải mã đối xứng chính
//Convert bytes to AES SecertKey SecretKey originalKey = new SecretKeySpec(decryptedKey , 0, decryptedKey .length, "AES"); Cipher aesCipher = Cipher.getInstance("AES"); aesCipher.init(Cipher.DECRYPT_MODE, originalKey); byte[] bytePlainText = aesCipher.doFinal(byteCipherText); String plainText = new String(bytePlainText);`
- 1. Sử dụng READ Binary để đọc thêm hơn 256 byte
- 2. Nhận dữ liệu chuỗi từ byte được mã hóa
- 3. Trình dữ liệu có nhanh hơn tập dữ liệu khi điền dữ liệu được không?
- 4. Không thể trao đổi dữ liệu được mã hóa với AES-256 giữa Java và PHP
- 5. Nhận lỗi java.lang.ArrayIndexOutOfBoundsException: quá nhiều dữ liệu cho khối RSA
- 6. Độ dài dữ liệu được trả lại từ CGImageGetDataProvider lớn hơn dự kiến
- 7. Nhận lỗi khi chèn dữ liệu khi sử dụng Truy vấn máy chủ được liên kết
- 8. Sử dụng Khóa công cộng RSA để giải mã một chuỗi đã được mã hóa bằng Khóa riêng RSA
- 9. Cửa hàng không được đăng ký lâu dài bằng cách sử dụng Dữ liệu chính
- 10. Chuyển đổi kiểu dữ liệu 'dài' để byte mảng
- 11. Ổ C++ socket 256 byte
- 12. Có loại dữ liệu .NET nhỏ hơn byte không?
- 13. IllegalStateException: không thể nhận được hiện vật khi dữ liệu chưa được tải cho Guava 12.0?
- 14. dòng C# đã nhận được tất cả dữ liệu?
- 15. Nhận Chiều dài dữ liệu với Entity Framework (để xác nhận độ dài dữ liệu trên một dịch vụ WCF)
- 16. cách sử dụng RSA để mã hóa các tệp (dữ liệu lớn) trong C#
- 17. Java Multicast Gửi dữ liệu, không nhận được
- 18. Dữ liệu mã hóa AES 256 bit của Android
- 19. boost :: asio :: async_write, ghi dữ liệu lớn hơn 65536 byte
- 20. Làm cách nào tôi có thể nhận được một phạm vi byte cụ thể trong dữ liệu varbinary?
- 21. Nhận EXC_BAD_ACCESS khi sử dụng dispatch_async với Dữ liệu chính
- 22. Có thể nhận khóa riêng RSA biết khóa công cộng và tập hợp các mục nhập "dữ liệu gốc => dữ liệu được mã hóa" không?
- 23. đúng nhận được dữ liệu từ một (sắp xếp) JTable
- 24. Lỗi ca cao 256 dữ liệu lõi
- 25. TStringStream bị hỏng khi nhận được sử dụng recv (winsock's)?
- 26. SerialPort không nhận được bất kỳ dữ liệu
- 27. Nhận dữ liệu sai khi sử dụng SimpleDateFormat.parse()
- 28. Sử dụng byte làm kiểu dữ liệu khóa chính
- 29. PHP lỗi, không có dữ liệu nhận được
- 30. Dịch vụ web WCF không nhận được dữ liệu lớn
Chỉ cần sử dụng HTTPS và mã hóa sẽ được thực hiện một cách minh bạch. – zaph