안 드 로 이 드 가 서명 한 SHA 1 을 이용 하여 안전 검 사 를 하 는 방법 중 하나(추천)

최근 안 드 로 이 드 프로젝트 에서 바 이 두 맵 의 API 를 사 용 했 습 니 다.바 이 두 맵 key 를 신청 할 때'서명 한 SHA 1'과'클 라 이언 트 패키지 이름'을 입력 한 다음 바 이 두 가 키 를 만 들 어 줘 야 합 니 다.
그래서 바 이 두 는 왜 우리 클 라 이언 트 가 서명 한 SHA 1 값 이 필요 합 니까?
첫 번 째 생각 은 바 이 두 가 우리 가 입력 한 매개 변수 SHA 1 과 가방 이름 을 가지 고 열 알고리즘 을 계산 하여 key 를 만들어 우리 에 게 되 돌려 주 는 것 이다.
이 아 이 디 어 를 증명 하기 위해 demo 를 써 서 테스트 를 했 습 니 다.안 드 로 이 드 가 가방 이름 을 가 져 오 는 방법 은 간단 하지만 클 라 이언 트 에서 keystore 의 지문 SHA 1 을 가 져 와 야 합 니 다.
각종 자 료 를 찾 고 분석 해 야 방법 을 얻 을 수 있다.
첫째,우선,apk 패키지 의 META-INF 디 렉 터 리 를 보급 합 니 다.
우 리 는 이미 알 고 있 는 것 은 Android 가 모든 APK 파일 에 서명 을 하고 APK 파일 을 설치 할 때 시스템 은 서명 정 보 를 비교 하여 프로그램의 완전 성 을 판단 하여 이 APK 파일 이 설치 할 수 있 는 지,어느 정도 안전 한 목적 을 달성 할 수 있 는 지 를 결정 한 다 는 것 이다.
APK 파일 을 지정 하고 압축 을 풀 면 META-INFO 폴 더 를 볼 수 있 습 니 다.이 폴 더 아래 에 세 개의 파일 이 있 습 니 다.각각 MANIFEST.MF,CERT.SF 와 CERT.RSA 입 니 다.이 세 개의 문 서 는 각각 다음 과 같은 의 미 를 나타 낸다.
(1)MANIFEST.MF:요약 파일 입 니 다.프로그램 은 APK 패키지 에 있 는 모든 파일(entry)을 옮 겨 다 니 며,비 폴 더 에 서명 하지 않 은 파일 을 각각 SHA 1 로 요약 정 보 를 만 들 고 Base 64 로 인 코딩 합 니 다.apk 패키지 의 파일 을 변경 하면 apk 설치 검사 시 변 경 된 파일 요약 정보 가 MANIFEST.MF 의 검사 정보 와 다 르 기 때문에 프로그램 이 성공 적 으로 설치 되 지 못 합 니 다.
설명:공격 자가 프로그램의 내용 을 수정 하고 새로운 요약 을 다시 만 들 었 다 면 검증 을 통과 할 수 있 기 때문에 매우 간단 한 검증 이다.
(2)CERT.SF:요약 에 대한 서명 파일 입 니 다.이전 단계 에 생 성 된 MANIFEST.MF 에 SHA1-RSA 알고리즘 을 사용 하여 개발 자의 비밀 키 로 서명 합 니 다.설치 할 때 공개 키 만 사용 해 야 복호화 할 수 있 습 니 다.복호화 후 암호 화 되 지 않 은 요약 정보(즉,MANIFEST.MF 파일)와 비교 하고,일치 하면 내용 이 이상 하 게 수정 되 지 않 았 음 을 나타 낸다.
설명:이 단계 에서 개발 자가 프로그램 내용 을 수정 하고 새로운 요약 파일 을 생 성 하 더 라 도 공격 자 는 개발 자의 비밀 키 가 없 기 때문에 정확 한 서명 파일(CERT.SF)을 생 성 할 수 없습니다.시스템 은 프로그램 을 검증 할 때 잘못된 서명 파일 을 개발 자 공개 키 로 복호화 하여 얻 은 결과 와 요약 파일(MANIFEST.MF)이 대응 하지 않 기 때문에 검 사 를 통과 할 수 없고 파일 을 성공 적 으로 설치 할 수 없습니다.
(3)CERT.RSA 파일 에는 공개 키,사용 하 는 암호 화 알고리즘 등 정보 가 저 장 됩 니 다.
설명:시스템 이 서명 파일 을 복호화 하 는데 필요 한 공개 키 는 이 파일 에서 꺼 낸 것 입 니 다.
결론:위의 정 리 를 통 해 알 수 있 듯 이 META-INFO 에서 그 파일 이 서로 연결 되 어 안 드 로 이 드 프로그램의 안전성 을 확보 합 니 다.(개발 자의 프로그램 이 공격 자 에 의 해 수정 되 지 않도록 방지 할 뿐 개발 자의 공개 키 가 공격 자 에 게 받 거나 개발 자가 공격 프로그램 을 개발 하면 Android 시스템 에서 감지 할 수 없습니다.)
우 리 는 apk 패 키 지 를 풀 고 명령 keytool-printcert-file CERT.RSA 를 사용 하여 CERT.RSA 를 볼 것 입 니 다.그림 과 같 습 니 다.

정 답 은 분명 하 다.CERT.RSA 파일 에는 서명 에 대한 정보 가 저장 되 어 있다.
다음 코드 를 사용 하여 인증서 정 보 를 얻 을 때:

/**
	 *              
	 * 
	 * @param context
	 * @param packName
	 * @author SHANHY
	 */
	public static void getSingInfo(Context context, String packName) {
		try {
			PackageInfo packageInfo = context.getPackageManager().getPackageInfo(packName, PackageManager.GET_SIGNATURES);
			Signature[] signs = packageInfo.signatures;
			Signature sign = signs[0];
			parseSignature(sign.toByteArray());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void parseSignature(byte[] signature) {
		try {
			CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
			X509Certificate cert = (X509Certificate) certFactory.generateCertificate(new ByteArrayInputStream(signature));
			String pubKey = cert.getPublicKey().toString();
			String signNumber = cert.getSerialNumber().toString();
			Log.d(TAG, "pubKey = " + pubKey);//     16     
			Log.d(TAG, "signNumber = " + signNumber);
		} catch (Exception e) {
			e.printStackTrace();
		}
}
API 를 보면 X509Certificate 클래스 는 SHA 1 값 을 직접 얻 을 수 있 는 방법 을 제공 하지 않 았 음 을 알 수 있다.
서명 파일 의 암호 화 알고리즘 을 연구 한 후에 우 리 는 Publickey 에 따라 SHA 1 의 값 을 계산 할 수 있 고 계산 방법 은 다음 과 같다.
>X509Certificate 의 getEncoded()방법 을 통 해 공개 키 의 바이트 배열 을 얻 을 수 있 습 니 다.
>Message Digest 를 사용 하여 바이트 배열 을 SHA 1 의 degest 로 처리 하여 새로운 바이트 배열 을 얻 습 니 다.
>그리고 새 바이트 배열 을 16 진수 로 변환 하여 인증서 파일 의 지문 SHA 1 을 얻 습 니 다.
더 자세 한 암호 화 알고리즘 은 자바 서명 인증서 규칙 을 연구 할 수 있 습 니 다.
클 라 이언 트 가 시 작 될 때 서버 인 터 페 이 스 를 호출 하여 파일 CERT.RSA 를 흐 르 는 방식 으로 서버 에 전달 하고 서버 는 위 에서 캡 처 한 명령 을 사용 하여 SHA 1 값 을 얻어 클 라 이언 트 에 게 되 돌려 주 며 클 라 이언 트 는 이 값 을 메모리 변수 에 기록 하여 사용 하 는 것 입 니 다.
주:저희 가 받 은 인증서 지문 SHA 1 값 은 메모리 변수 에 저장 하지 않 아 도 됩 니 다.
아래 에 기타 인증서 와 관련 된 코드 를 동봉 합 니 다.
JAVA 가 비밀 키 정 보 를 가 져 오 는 코드:

public static void main(String[] args) {
		
		try {
			//          -                
			FileInputStream fis2 = new FileInputStream("G:\\test.keystore");
			KeyStore ks = KeyStore.getInstance("JKS"); //      
			char[] kspwd = "test".toCharArray(); //      
			char[] keypwd = "test".toCharArray(); //     
			String alias = "test";//   
			ks.load(fis2, kspwd); //     
			PrivateKey pk2 = (PrivateKey) ks.getKey(alias, keypwd); //       
			fis2.close();
//			Cipher c2 = Cipher.getInstance("RSA/ECB/PKCS1Padding");//jdk    
			Cipher c2 = Cipher.getInstance("RSA/ECB/NoPadding");//android    
			c2.init(Cipher.DECRYPT_MODE, pk2);
			
			String priKey = pk2.toString();
			System.out.println("priKey = " + priKey);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}
JAVA 가 공개 키 정 보 를 가 져 오 는 코드:

public static void main(String[] args) throws Exception {
		X509Certificate certificate = readSignatureBlock(new FileInputStream("G:/META-INF/CERT.RSA"));
		RSAPublicKey pk = (RSAPublicKey) certificate.getPublicKey();
		sun.security.rsa.RSAPublicKeyImpl ppk = (sun.security.rsa.RSAPublicKeyImpl) pk;
		System.out.println(ppk.getModulus());//      
		System.out.println(ppk.getModulus().toString(16));//       
		System.out.println(ppk.getPublicExponent());// 65537
		System.out.println(ppk.getAlgorithm());
		System.out.println(ppk.getFormat());
		System.out.println(ppk.getAlgorithmId());
		System.out.println(ppk.getPublicExponent().toString(16));// 10001
		System.out.println(new BigInteger(ppk.getEncoded()).toString(16));
		//   new
		// BigInteger(ppk.getEncoded()).toString(16)         ppk.getModulus().toString(16)    ppk.getPublicExponent().toString(16)。

		//        RSA      ,       Modulus,      。
		InputStream in2 = new FileInputStream("G:/META-INF/CERT.RSA");
		byte[] bs = new byte[2048];
		int len = in2.read(bs);
		byte[] bs2 = new byte[len];
		System.arraycopy(bs, 0, bs2, 0, len);
		System.out.println(new BigInteger(bs2).toString(16));//    16         。
	}
SHA 1 암호 코드:

public class SHA1 {
  private final int[] abcde = {
      0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 
    }; 
  //          
  private int[] digestInt = new int[5]; 
  //                
  private int[] tmpData = new int[80]; 
  //   sha-1   
  private int process_input_bytes(byte[] bytedata) { 
    //       
    System.arraycopy(abcde, 0, digestInt, 0, abcde.length); 
    //          , 10      
    byte[] newbyte = byteArrayFormatData(bytedata); 
    //                 
    int MCount = newbyte.length / 64; 
    //                 
    for (int pos = 0; pos < MCount; pos++) { 
      //            16     ,    tmpData  16       
      for (int j = 0; j < 16; j++) { 
        tmpData[j] = byteArrayToInt(newbyte, (pos * 64) + (j * 4)); 
      } 
      //        
      encrypt(); 
    } 
    return 20; 
  } 
  //             
  private byte[] byteArrayFormatData(byte[] bytedata) { 
    //  0   
    int zeros = 0; 
    //        
    int size = 0; 
    //        
    int n = bytedata.length; 
    //  64       
    int m = n % 64; 
    //     0       10      
    if (m < 56) { 
      zeros = 55 - m; 
      size = n - m + 64; 
    } else if (m == 56) { 
      zeros = 63; 
      size = n + 8 + 64; 
    } else { 
      zeros = 63 - m + 56; 
      size = (n + 64) - m + 64; 
    } 
    //             
    byte[] newbyte = new byte[size]; 
    //           
    System.arraycopy(bytedata, 0, newbyte, 0, n); 
    //     Append        
    int l = n; 
    //  1   
    newbyte[l++] = (byte) 0x80; 
    //  0   
    for (int i = 0; i < zeros; i++) { 
      newbyte[l++] = (byte) 0x00; 
    } 
    //       ,       8  ,    
    long N = (long) n * 8; 
    byte h8 = (byte) (N & 0xFF); 
    byte h7 = (byte) ((N >> 8) & 0xFF); 
    byte h6 = (byte) ((N >> 16) & 0xFF); 
    byte h5 = (byte) ((N >> 24) & 0xFF); 
    byte h4 = (byte) ((N >> 32) & 0xFF); 
    byte h3 = (byte) ((N >> 40) & 0xFF); 
    byte h2 = (byte) ((N >> 48) & 0xFF); 
    byte h1 = (byte) (N >> 56); 
    newbyte[l++] = h1; 
    newbyte[l++] = h2; 
    newbyte[l++] = h3; 
    newbyte[l++] = h4; 
    newbyte[l++] = h5; 
    newbyte[l++] = h6; 
    newbyte[l++] = h7; 
    newbyte[l++] = h8; 
    return newbyte; 
  } 
  private int f1(int x, int y, int z) { 
    return (x & y) | (~x & z); 
  } 
  private int f2(int x, int y, int z) { 
    return x ^ y ^ z; 
  } 
  private int f3(int x, int y, int z) { 
    return (x & y) | (x & z) | (y & z); 
  } 
  private int f4(int x, int y) { 
    return (x << y) | x >>> (32 - y); 
  } 
  //          
  private void encrypt() { 
    for (int i = 16; i <= 79; i++) { 
      tmpData[i] = f4(tmpData[i - 3] ^ tmpData[i - 8] ^ tmpData[i - 14] ^ 
          tmpData[i - 16], 1); 
    } 
    int[] tmpabcde = new int[5]; 
    for (int i1 = 0; i1 < tmpabcde.length; i1++) { 
      tmpabcde[i1] = digestInt[i1]; 
    } 
    for (int j = 0; j <= 19; j++) { 
      int tmp = f4(tmpabcde[0], 5) + 
        f1(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4] + 
        tmpData[j] + 0x5a827999; 
      tmpabcde[4] = tmpabcde[3]; 
      tmpabcde[3] = tmpabcde[2]; 
      tmpabcde[2] = f4(tmpabcde[1], 30); 
      tmpabcde[1] = tmpabcde[0]; 
      tmpabcde[0] = tmp; 
    } 
    for (int k = 20; k <= 39; k++) { 
      int tmp = f4(tmpabcde[0], 5) + 
        f2(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4] + 
        tmpData[k] + 0x6ed9eba1; 
      tmpabcde[4] = tmpabcde[3]; 
      tmpabcde[3] = tmpabcde[2]; 
      tmpabcde[2] = f4(tmpabcde[1], 30); 
      tmpabcde[1] = tmpabcde[0]; 
      tmpabcde[0] = tmp; 
    } 
    for (int l = 40; l <= 59; l++) { 
      int tmp = f4(tmpabcde[0], 5) + 
        f3(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4] + 
        tmpData[l] + 0x8f1bbcdc; 
      tmpabcde[4] = tmpabcde[3]; 
      tmpabcde[3] = tmpabcde[2]; 
      tmpabcde[2] = f4(tmpabcde[1], 30); 
      tmpabcde[1] = tmpabcde[0]; 
      tmpabcde[0] = tmp; 
    } 
    for (int m = 60; m <= 79; m++) { 
      int tmp = f4(tmpabcde[0], 5) + 
        f2(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4] + 
        tmpData[m] + 0xca62c1d6; 
      tmpabcde[4] = tmpabcde[3]; 
      tmpabcde[3] = tmpabcde[2]; 
      tmpabcde[2] = f4(tmpabcde[1], 30); 
      tmpabcde[1] = tmpabcde[0]; 
      tmpabcde[0] = tmp; 
    } 
    for (int i2 = 0; i2 < tmpabcde.length; i2++) { 
      digestInt[i2] = digestInt[i2] + tmpabcde[i2]; 
    } 
    for (int n = 0; n < tmpData.length; n++) { 
      tmpData[n] = 0; 
    } 
  } 
  // 4          
  private int byteArrayToInt(byte[] bytedata, int i) { 
    return ((bytedata[i] & 0xff) << 24) | ((bytedata[i + 1] & 0xff) << 16) | 
    ((bytedata[i + 2] & 0xff) << 8) | (bytedata[i + 3] & 0xff); 
  } 
  //      4     
  private void intToByteArray(int intValue, byte[] byteData, int i) { 
    byteData[i] = (byte) (intValue >>> 24); 
    byteData[i + 1] = (byte) (intValue >>> 16); 
    byteData[i + 2] = (byte) (intValue >>> 8); 
    byteData[i + 3] = (byte) intValue; 
  } 
  //               
  private static String byteToHexString(byte ib) { 
    char[] Digit = { 
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 
        'D', 'E', 'F' 
      }; 
    char[] ob = new char[2]; 
    ob[0] = Digit[(ib >>> 4) & 0X0F]; 
    ob[1] = Digit[ib & 0X0F]; 
    String s = new String(ob); 
    return s; 
  } 
  //                 
  private static String byteArrayToHexString(byte[] bytearray) { 
    String strDigest = ""; 
    for (int i = 0; i < bytearray.length; i++) { 
      strDigest += byteToHexString(bytearray[i]); 
    } 
    return strDigest; 
  } 
  //   sha-1  ,          
  public byte[] getDigestOfBytes(byte[] byteData) { 
    process_input_bytes(byteData); 
    byte[] digest = new byte[20]; 
    for (int i = 0; i < digestInt.length; i++) { 
      intToByteArray(digestInt[i], digest, i * 4); 
    } 
    return digest; 
  } 
  //   sha-1  ,             
  public String getDigestOfString(byte[] byteData) { 
    return byteArrayToHexString(getDigestOfBytes(byteData)); 
  } 
  public static void main(String[] args) { 
    String data = "1234556"; 
    System.out.println(data);
    String digest = new SHA1().getDigestOfString(data.getBytes()); 
    System.out.println(digest);
    
    // System.out.println( ToMD5.convertSHA1(data).toUpperCase());
  } 
} 
이상 의 안 드 로 이 드 는 서명 한 SHA 1 을 이용 하여 안전 검 사 를 하 는 방법 중 하나(추천)는 바로 편집장 이 여러분 에 게 공유 한 모든 내용 입 니 다.여러분 께 참고 가 되 고 저희 도 많이 응원 해 주시 기 바 랍 니 다.

좋은 웹페이지 즐겨찾기