AES,DES,RSA 등 암호 화 복호화 실패 원인
24810 단어 원본 코드 읽 기
우 리 는 위 챗 결제 나 다른 제3자 인터페이스 로 대칭 또는 비대 칭 암호 화 를 사용 할 때 공개 키 와 비밀 키 가 모두 정확 하지만 제3자 서버 는 복호화 에 실 패 했 습 니 다.
오류 원인 복호화
1.로 컬 문자열 인 코딩 과 암호 화 후 바이트 인 코딩 이 대응 하지 않 습 니 다.자바 에서 String 류 의 getBytes 방법 은 다음 과 같 습 니 다.
public byte[] getBytes() {
return StringCoding.encode(value, 0, value.length);
}
이 방법 은 StringCoding 의 정적 encode 방법 을 호출 하 는 것 입 니 다.encode 방법 은 다음 과 같 습 니 다.
static byte[] encode(char[] ca, int off, int len) {
String csn = Charset.defaultCharset().name();
try {
// Charset
return encode(csn, ca, off, len);
} catch (UnsupportedEncodingException x) {
warnUnsupportedCharset(csn);
}
try {
// ISO-8859-1
return encode("ISO-8859-1", ca, off, len);
} catch (UnsupportedEncodingException x) {
// If this code is hit during VM initialization, MessageUtils is
// the only way we will be able to get any kind of error message.
MessageUtils.err("ISO-8859-1 charset not available: "
+ x.toString());
// If we can not find ISO-8859-1 (a required encoding) then things
// are seriously wrong with the installation.
System.exit(1);
return null;
}
}
Charset 류 의 기본 인 코딩 이 무엇 인지 다시 봅 시다.코드 는 다음 과 같 습 니 다.
public static Charset defaultCharset() {
//defaultCharset Charset volatile
if (defaultCharset == null) {
synchronized (Charset.class) {
// , UTF-8
String csn = AccessController.doPrivileged(
new GetPropertyAction("file.encoding"));
Charset cs = lookup(csn);
if (cs != null)
defaultCharset = cs;
else
defaultCharset = forName("UTF-8");
}
}
return defaultCharset;
}
System.getProperty("file.encoding")에서 가 져 온 인 코딩 은 제 가 IDEA 에 jvm 변 수 를 설정 한 file.endcoding 과 일치 합 니 다.file.endcoding 변 수 를 설정 하지 않 으 면 기본 시스템 인 코딩 입 니 다.시스템 인 코딩 이 지원 되 지 않 으 면 기본 인 코딩 UTF-8 입 니 다.물론 자바 에는 지원 할 수 없 는 인 코딩 이 거의 없습니다.sun 가방 에 StandardCharsets 는 천 여 가지 인 코딩 을 제공 합 니 다.이로써 우 리 는 문자열 이 바이트 그룹 을 바 꿀 때 기본적으로 시스템 인 코딩 이나 UTF-8,윈도 우즈 에서 기본 gbk,linux 에서 기본 ISO 8859-1 이라는 것 을 알 게 되 었 다.보통 저 희 는 AES 암호 화 를 사용 하면 다음 과 같은 방식 을 사용 합 니 다.
public static byte[] encrypt(String content, String password) {
try {
Cipher cipher = Cipher.getInstance("AES");//
byte[] byteContent = content.getBytes();
cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(password));//
return cipher.doFinal(byteContent);//
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return null;
}
/**
*
*
* @return
*/
private static SecretKeySpec getSecretKey(String password) {
// KeyGenerator
KeyGenerator kg = null;
try {
kg = KeyGenerator.getInstance("AES");
//AES 128
kg.init(128, new SecureRandom(password.getBytes()));
//
SecretKey secretKey = kg.generateKey();
return new SecretKeySpec(secretKey.getEncoded(), "AES");// AES
} catch (NoSuchAlgorithmException ex) {
ex.printStackTrace();
}
return null;
}
우 리 는 다음 과 같은 테스트 를 채택 한다.
public static void main(String[] args) throws UnsupportedEncodingException {
//
System.out.println(System.getProperty("file.encoding"));
String str = "abc123 ";
byte[] bytes = encrypt(str, "123456");
System.out.println(bytes.length == new String(bytes).getBytes().length);
System.out.println(bytes.length == new String(bytes, "UTF-8").getBytes("UTF-8").length);
System.out.println(bytes.length == new String(bytes, "GBK").getBytes("GBK").length);
System.out.println(bytes.length == new String(bytes, "ISO8859-1").getBytes("ISO8859-1").length);
}
결 과 는 다음 과 같다.
UTF-8
false
false
true
true
종합 적 으로 알 수 있 듯 이 sun 패키지 의 Cipher 암호 화 를 사용 하여 되 돌아 오 는 by te[]인 코딩 방식 은 ISO 8859-1 입 니 다.이로써 우 리 는 이 암호 화 방식 의 기본 인 코딩 이 원인 임 을 알 게 되 었 습 니 다.
어떻게 피 할 것 인가
1.암호 화 후 byte 배열 을 되 돌려 16 진 문자열 이나 base 64 인 코딩 문자열 로 변환 합 니 다.다음 과 같 습 니 다.
String str = "abc123 ";
System.out.println(new String(str.getBytes(),"UTF-8"));
byte[] bytes = encrypt(str, "123456");
String result= Hex.bytes2Hex(bytes);
System.out.println(new String(decrypt(Hex.hexToBytes(result),"123456")));
결 과 는 다음 과 같다.
abc123
abc123
복호화 할 때 문자열 을 복호화 하여 아래 의 이상 을 방지 해 야 합 니 다.
javax.crypto.BadPaddingException: Given final block not properly padded
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:966)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:824)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:436)
at javax.crypto.Cipher.doFinal(Cipher.java:2165)
2.암호 화 된 내용 이 위 챗 등 제3자 에 게 호출 될 때 보통 제3자 가 디 코딩 을 하지 않 기 때문에 이때 우 리 는 암호 화 된 byte[]를 string 으로 전환 할 때 iso 8859-1 인 코딩 을 설정 할 수 밖 에 없다.그렇지 않 으 면 제3자 가 계속 복호화 에 실 패 했 습 니 다.