Có một vài giải pháp thường được trích dẫn cho vấn đề này. Thật không may, cả hai điều này đều không thỏa đáng:
- Cài đặt các tập tin chính sách sức mạnh không giới hạn . Mặc dù đây có lẽ là giải pháp phù hợp cho máy trạm phát triển của bạn, nhưng nó nhanh chóng trở thành rắc rối lớn (nếu không phải là rào cản) khi người dùng không có kỹ thuật cài đặt các tệp trên mọi máy tính. Không có cách nào để phân phối các tệp với chương trình của bạn; chúng phải được cài đặt trong thư mục JRE (thậm chí có thể chỉ đọc do quyền).
- Bỏ qua API JCE và sử dụng một thư viện mật mã khác như Bouncy Castle . Cách tiếp cận này đòi hỏi một thư viện thêm 1 MB, có thể là một gánh nặng đáng kể tùy thuộc vào ứng dụng. Nó cũng cảm thấy ngớ ngẩn khi sao chép chức năng có trong các thư viện tiêu chuẩn. Rõ ràng, API cũng hoàn toàn khác với giao diện JCE thông thường. (BC không triển khai nhà cung cấp JCE, nhưng điều đó không có ích vì các giới hạn cường độ chính được áp dụng trước khi bàn giao cho việc triển khai.) Giải pháp này cũng sẽ không cho phép bạn sử dụng bộ mật mã TLS (SSL) 256 bit, bởi vì các thư viện TLS tiêu chuẩn gọi JCE trong nội bộ để xác định bất kỳ hạn chế nào.
Nhưng sau đó có sự phản ánh. Có điều gì bạn không thể làm bằng cách sử dụng sự phản chiếu?
private static void removeCryptographyRestrictions() {
if (!isRestrictedCryptography()) {
logger.fine("Cryptography restrictions removal not needed");
return;
}
try {
/*
* Do the following, but with reflection to bypass access checks:
*
* JceSecurity.isRestricted = false;
* JceSecurity.defaultPolicy.perms.clear();
* JceSecurity.defaultPolicy.add(CryptoAllPermission.INSTANCE);
*/
final Class<?> jceSecurity = Class.forName("javax.crypto.JceSecurity");
final Class<?> cryptoPermissions = Class.forName("javax.crypto.CryptoPermissions");
final Class<?> cryptoAllPermission = Class.forName("javax.crypto.CryptoAllPermission");
final Field isRestrictedField = jceSecurity.getDeclaredField("isRestricted");
isRestrictedField.setAccessible(true);
final Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(isRestrictedField, isRestrictedField.getModifiers() & ~Modifier.FINAL);
isRestrictedField.set(null, false);
final Field defaultPolicyField = jceSecurity.getDeclaredField("defaultPolicy");
defaultPolicyField.setAccessible(true);
final PermissionCollection defaultPolicy = (PermissionCollection) defaultPolicyField.get(null);
final Field perms = cryptoPermissions.getDeclaredField("perms");
perms.setAccessible(true);
((Map<?, ?>) perms.get(defaultPolicy)).clear();
final Field instance = cryptoAllPermission.getDeclaredField("INSTANCE");
instance.setAccessible(true);
defaultPolicy.add((Permission) instance.get(null));
logger.fine("Successfully removed cryptography restrictions");
} catch (final Exception e) {
logger.log(Level.WARNING, "Failed to remove cryptography restrictions", e);
}
}
private static boolean isRestrictedCryptography() {
// This matches Oracle Java 7 and 8, but not Java 9 or OpenJDK.
final String name = System.getProperty("java.runtime.name");
final String ver = System.getProperty("java.version");
return name != null && name.equals("Java(TM) SE Runtime Environment")
&& ver != null && (ver.startsWith("1.7") || ver.startsWith("1.8"));
}
Chỉ cần gọi removeCryptographyRestrictions()
từ trình khởi tạo tĩnh hoặc như vậy trước khi thực hiện bất kỳ hoạt động mã hóa nào.
Phần JceSecurity.isRestricted = false
này là tất cả những gì cần thiết để sử dụng mật mã 256 bit trực tiếp; tuy nhiên, không có hai hoạt động khác, Cipher.getMaxAllowedKeyLength()
vẫn sẽ tiếp tục báo cáo 128 và bộ mật mã TLS 256 bit sẽ không hoạt động.
Mã này hoạt động trên Oracle Java 7 và 8 và tự động bỏ qua quy trình trên Java 9 và OpenJDK khi không cần thiết. Rốt cuộc là một hack xấu xí, có khả năng nó không hoạt động trên máy ảo của các nhà cung cấp khác.
Nó cũng không hoạt động trên Oracle Java 6, vì các lớp JCE riêng bị che khuất ở đó. Việc obfuscation không thay đổi từ phiên bản này sang phiên bản khác, do đó về mặt kỹ thuật vẫn có thể hỗ trợ Java 6.