AES,DES,RSA 등 암호 화 복호화 실패 원인

24810 단어 원본 코드 읽 기
AES,DES,RSA 등 암호 화 복호화 실패 원인
우 리 는 위 챗 결제 나 다른 제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자 가 계속 복호화 에 실 패 했 습 니 다.

좋은 웹페이지 즐겨찾기