2017-12-11 12 views
1

저는 신입 회원입니다. 나는 안드로이드 클라이언트에서 파이썬 서버로 솔루션 검증 서명을 찾기 위해 이틀 동안 기다렸습니다. 먼저 키 쌍을 생성하고 개인 키로 서명을 생성합니다. 감사합니다 pedrofb 나는 전체 코드를 업데이 트했습니다. 파이썬 서버에서 완료 확인하십시오.안드로이드/파이썬 서명을 확인하는 방법 SHA256withRSA 및 PKCS1 패딩

protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 

    KeyPairGenerator keyPairGenerator = null; 
    try { 
     KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 
     keyStore.load(null); 
     //keyStore.deleteEntry("key1"); 
     keyPairGenerator = KeyPairGenerator.getInstance(
       KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore"); 
     try { 
      KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder("key1", KeyProperties.PURPOSE_SIGN) 
        .setKeySize(2048) 
        .setBlockModes(KeyProperties.BLOCK_MODE_CBC) 
        .setDigests(KeyProperties.DIGEST_SHA256) 
        .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1); 
      keyPairGenerator.initialize(builder.build()); 
     } catch (InvalidAlgorithmParameterException e) { 
      e.printStackTrace(); 
     } 
     KeyPair keyPair = keyPairGenerator.generateKeyPair(); 
     PrivateKey privateKey = (PrivateKey) keyStore.getKey("key1", null); 
     PublicKey publicKey = keyStore.getCertificate("key1").getPublicKey(); 
     String publicKeyStr = Base64.encodeToString(publicKey.getEncoded(), Base64.NO_WRAP); 
     Log.d("Hahaha", publicKeyStr); 
     Signature signature = Signature.getInstance("SHA256withRSA"); 
     signature.initSign(privateKey); 
     String data = "haha"; 
     signature.update(data.getBytes()); 
     byte[] signatureBytes = signature.sign(); 
     String signatureBase64 = Base64.encodeToString(signatureBytes, Base64.NO_WRAP); 
     Log.d("Hahaha", signatureBase64); 
     Signature verifySignature = Signature.getInstance("SHA256withRSA"); 
     verifySignature.initVerify(publicKey); 
     verifySignature.update(data.getBytes()); 
     boolean isVerify = verifySignature.verify(Base64.decode(signatureBase64, Base64.NO_WRAP)); 
     Log.d("Hahaha", isVerify + ""); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 

public static String sha256(String rawString){ 
    MessageDigest shaDigest; 
    byte[] data; 
    try { 
     data = rawString.getBytes("UTF-8"); 
     shaDigest = MessageDigest.getInstance("SHA-256"); 
    } catch (Exception e) { 
     return null; 
    } 
    shaDigest.update(data); 
    return toHex(shaDigest.digest()); 
} 

public static String toHex(byte[] tmp) { 
    char hexDigits[] = 
      {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 
        'e', 'f'}; 
    int nBytesLen = tmp.length; 
    char str[] = new char[nBytesLen * 2]; 
    int k = 0; 
    for (byte byte0 : tmp) { 
     str[k++] = hexDigits[byte0 >>> 4 & 0xf]; 
     str[k++] = hexDigits[byte0 & 0xf]; 
    } 
    return new String(str); 
} 

및 서버, 내가 서명을 확인하는 데 PKCS1_v1_5를 사용, 그것은 안드로이드 클라이언트에서 전송됩니다

from Crypto.Signature import PKCS1_v1_5 
from Crypto.Hash import SHA256 
from Crypto.PublicKey import RSA 
from base64 import b64decode 

keyDER = b64decode(open('public.der').read()) 
key = RSA.importKey(keyDER) 
message = "haha" 
h = SHA256.new(message) 
print h.hexdigest() 
signature = b64decode(open('signature.der').read()) 
verifier = PKCS1_v1_5.new(key) 
if verifier.verify(h, signature): 
    print "The signature is authentic." 
else: 
    print "The signature is not authentic." 

나는 클라이언트와 서버, 그것의 동일한 해시 데이터를 확인해야하지만 false를 반환 verifier.verify , public.der은 변수 PublicKeyStr의 값이고 signature.der은 변수의 값입니다 SignatureBase64 도와주세요. [코멘트 해결]

+0

데이터는 *하지 * 같은, 그것은 자바에 "하하하"입니다 측면과 "하하"비단뱀 쪽. –

+0

몇 가지 오류가 있습니다. 1) Java 코드와 서명 및 16 진수 값이 두 번 해시됩니다. 'signature.update (data.getBytes());'와'verifySignature.update (sha256 (data) .getBytes());와'signature.update (sha256 (data) .getBytes()); '.setBlockModes (KeyProperties.BLOCK_MODE_CBC)'를 제거하십시오. 3)'onCreate'가 호출 될 때마다 키 쌍을 만들어야합니다. – pedrofb

+0

고맙지 만 클라이언트를 확인합니다. 사실, verifySignature 나는 그것이 안드로이드에서 작동 확인 만 만들면. 파이썬 측면과 자바 측 모두에 서명하는 데이터는 "haha"입니다. 파이썬에서 h.hexdigest()와 sha256 (데이터) .getBytes()는 같은 값을 반환합니다. – hai

답변

0

당신은 자바 코드에서 자바 코드

1)에서 몇 가지 오류를 가지고, 당신은 SHA256 두 번 메시지를 소화하고 16 진수 값이 아닌 바이너리 메시지에 서명한다.

java에서 SHA256withRSA은 여러 작업을 수행하고 처음에는 SHA256 다이제스트 알고리즘을 메시지에 적용한 다음 RSA PKCS # 1 v1.5 알고리즘을 적용합니다. 파이썬에서 (또는 다른 언어)을 그것은

signature.update(data.getBytes()); 
verifySignature.update(data.getBytes()); 

2) .setBlockModes(KeyProperties.BLOCK_MODE_CBC) 제거를 두 단계

변경

signature.update(sha256(data).getBytes()); 
verifySignature.update(sha256(data).getBytes()); 

에 프로그래밍 방식으로 수행 할 수 있습니다. 이 암호화 매개 변수가없는 당신은 한 번 키 쌍을 생성해야합니다

3) 디지털 서명,라고 onCreate 없습니다마다에 appliable입니다