GetEncoded trả về một bản sao của khóa bí mật (do đó việc xóa không ảnh hưởng đến dữ liệu khóa bí mật), và phá hủy theo mặc định ném DestroyFailedException mà tệ hơn vô dụng. Nó cũng chỉ có sẵn trong 1,8+ vì vậy Android là ra khỏi may mắn. Đây là một hack sử dụng nội tâm để (1) gọi phá hủy nếu có sẵn và không ném một ngoại lệ, nếu không (2) không phải là dữ liệu quan trọng và thiết lập các tham chiếu đến null.
package kiss.cipher;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import javax.crypto.spec.SecretKeySpec;
/**
* Created by wmacevoy on 10/12/16.
*/
public class CloseableKey implements AutoCloseable {
// forward portable to JDK 1.8 to destroy keys
// but usable in older JDK's
static final Method DESTROY;
static final Field KEY;
static {
Method _destroy = null;
Field _key = null;
try {
Method destroy = SecretKeySpec.class.getMethod("destroy");
SecretKeySpec key = new SecretKeySpec(new byte[16], "AES");
destroy.invoke(key);
_destroy = destroy;
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
}
try {
_key = SecretKeySpec.class.getDeclaredField("key");
_key.setAccessible(true);
} catch (NoSuchFieldException | SecurityException ex) {
}
DESTROY = _destroy;
KEY = _key;
}
static void close(SecretKeySpec secretKeySpec) {
if (secretKeySpec != null) {
if (DESTROY != null) {
try {
DESTROY.invoke(secretKeySpec);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
throw new IllegalStateException("inconceivable: " + ex);
}
} else if (KEY != null) {
try {
byte[] key = (byte[]) KEY.get(secretKeySpec);
Arrays.fill(key, (byte) 0);
KEY.set(secretKeySpec, null);
} catch (IllegalAccessException | IllegalArgumentException ex) {
throw new IllegalStateException("inconceivable: " + ex);
}
}
}
}
public final SecretKeySpec secretKeySpec;
CloseableKey(SecretKeySpec _secretKeySpec) {
secretKeySpec = _secretKeySpec;
}
@Override
public void close() {
close(secretKeySpec);
}
}
Cách sử dụng điều này cũng giống như
try (CloseableKey key =
new CloseableKey(new SecretKeySpec(data, 0, 16, "AES"))) {
aesecb.init(Cipher.ENCRYPT_MODE, key.secretKeySpec);
}
tôi sử dụng giao diện có thể đóng vì thể bị phá hủy chỉ là một tính năng 1.8+. Phiên bản này hoạt động trên 1,7+ và khá hiệu quả (nó thực hiện một thử nghiệm phá hủy trên một chìa khóa để quyết định sử dụng lại nó).
Nguồn
2017-03-25 05:07:45
-1: * mọi thứ khác trong Java luôn được chuyển bằng tham chiếu * - Nooo, Java là * luôn * truyền theo giá trị! Lý do bạn không thể vượt qua * một đối tượng * theo giá trị, là bởi vì không có biến nào có thể chứa một đối tượng ở vị trí đầu tiên! – aioobe
@aioobe .. bạn chắc chắn chúng ta đang nói về cùng một Java? int được truyền theo giá trị, boolean được truyền theo giá trị, Integer là một tham chiếu, cũng như bất kỳ đối tượng, mảng, vv ... Java chuyển "một giá trị", mà thực sự là "tham chiếu" tới một đối tượng, do đó tài liệu tham khảo. –
@ Joachim .. Tôi đã đề cập đến "mảng byte đã cho", tuy nhiên tiếp tục làm rõ rằng có thể có một bản sao khác. –