반응형
Notice
Recent Posts
Recent Comments
Link
It's easy, if you try
[안드로이드 / Node.js] PrivateKey Signature, PublicKey Verify 본문
반응형
클라이언트의 Private Key로 서명한 Challenge Number를 서버로 보내 (기존 클라이언트에게 받은)Public Key 로 Verify 하는 과정
위 플로우 중 4, 6 번의 과정을 다룰 것이다.
Private Key 를 이용하여 Challenge Number 에 서명하기 (4번 과정) - Client
getDigitalSignature()
private static final String SIGNATURE_ALGORITHM = "SHA256withRSA";
...
public String getDigitalSignature(String packageName, String text) {
try{
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initSign(getPrivateKey(packageName));
byte[] data = text.getBytes();
signature.update(data);
byte[] signatureBytes = signature.sign();
String signatureStr = Base64.encodeToString(signatureBytes, Base64.NO_WRAP);
Log.d(TAG, "Signature:" + signatureStr);
return signatureStr;
} catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
Log.e(TAG, "error in digital signature" + e);
return null;
}
}
Public Key 를 이용하여 Verify - Client
verifySignature()
일단 먼저 Client에서 Sign 및 Verify 가 완벽히 이루어 져야 Server에 코드를 짜고 테스트 해볼 수 있을 거라 생각하였기 때문에 verify 함수도 구현하였다.
private static final String SIGNATURE_ALGORITHM = "SHA256withRSA";
...
public boolean verifySignature(String packageName, String signature, String original){
try{
Signature sig = Signature.getInstance(SIGNATURE_ALGORITHM); // getDigitalSignature와 같은 알고리즘 사용
sig.initVerify(getPublicKey(packageName));
byte[] data = original.getBytes();
sig.update(data);
boolean result = sig.verify(Base64.decode(signature, Base64.NO_WRAP));
Log.d(TAG, "signatureString result :" + result);
return result;
}catch(Exception e){
e.printStackTrace();
Log.e(TAG,"error for verify:" + e.getMessage());
return false;
}
}
- 처음엔 text에 서명한 값을 *String으로 변환하여 반환할 때, Base64를 이용하지 않고
return new String(signatureBytes, "UTF-8");
이와 같은 방식으로 *Encode, Decode 하였다. - -> verify 결과: false
- getDigitalSignature() 함수의 반환형을 String 아닌 byte[]로 반환하도록 코드를 수정하였다. (signature.sign() 값 형변환 x)
- -> verify 결과: true
즉, byte Array를 String으로 Encoding 하는 과정에서 데이터가 온전히 Encoding 되지 않는다는 뜻이었다.
하지만 서버에는 String 형태로 보내야해서 어떻게든 String으로 형변환을 해야했다ㅠㅠ .. 엄청 헤매다가 초반 RSA를 이용한 Encrypt, Decrypt 함수 작성시에 *Base64로 *Encoding 한 코드를 참고하여 Base64를 이용해 보았다. 아래와 같은 코드였다.
String signatureStr = Base64.encodeToString(signatureBytes, Base64.DEFAULT);
다른 포스팅에서 작성한 글('Base64를 이용하여 Encoding, Decoding시 주의할 점')에서 알 수 있듯이 디지털 서명은 암호화된 값과는 달리 길이가 길어서Base64.Default
를 이용하면 중간에 개행 문자(\n)가 삽입돼서 그런거였다.- -> verify 결과: false
String signatureStr = Base64.encodeToString(signatureBytes, Base64.NO_WRAP);
드디어 true가 나왔다.- NO_WRAP 은 개행 문자를 삽입하지 않고 한 줄로 encoding 한다.
- -> verify 결과: true
Public Key 를 이용하여 Verify하기 (6번 과정) - Server
app.post("/auth", function(req, res){
var signedCN = req.body.challenge_number; // Client에서 받아온 서명값
console.log("auth challenge_number from client : "+ signedCN);
const verifier = crypto.createVerify('sha256WithRSAEncryption'); // 알고리즘 Client와 일치해야함
verifier.update(challenge_number);
const verifyResult = verifier.verify(public_key, Buffer.from(signedCN,'base64'));
console.log("auth verify result: " + verifyResult);
var val = {'mode':"auth", 'result': verifyResult};
res.send(val);
});
challenge_number(2번에서 Client에 전송한 값) 와 public_key(Client의 Private Key 와 한 쌍, 1번 과정에서 받아옴) 는 이미 서버가 알고 있다.
클라이언트에서는 verify 결과가 true 였지만 서버 verify는 false여서 답답해하며 알아낸 것.
- Client와 동일한 알고리즘(sha256WithRSAEncryption)이 뭔지 알아내기 어려웠다.
- 계속 'RSA-SHA256'이 같은 알고리즘일 것이라 생각했고 검색 끝에 알아내게 되었다.
Buffer.from(signedCN,'base64'))
- 서명 값(signedCN)이 Base64*로 *Encoding 되어 왔기 때문에 똑같이 Base64*를 이용하여 *Decoding 해주어야 했다.
(https://stackoverflow.com/questions/53813676/sha256withrsa-signature-verification-in-nodejs-returning-false-every-time 감사합니다.. ) - Client에서는 update시에 challenge_number를 byte[]로 변환하기에
Buffer.from
을 이용해야하는 줄 알았는데 그냥 update에 넣어도 된다 !
- 서명 값(signedCN)이 Base64*로 *Encoding 되어 왔기 때문에 똑같이 Base64*를 이용하여 *Decoding 해주어야 했다.
- 예제 마다
Buffer.from
를 이용하여 Decoding 하는 객체가 달라서 너무 헷갈렸다ㅠ (challenge_number, public_key, signedCN 중 어느 것을 Decoding 하여야 하는지..? )
+) Private Key 를 이용하여 Sign (6번 과정) - Server
const signature = crypto.createSign('sha256WithRSAEncryption');
signature.update(challenge_number);
const sigresult = signature.sign(private_key);
-> 초반에 Node.js 자체에서 sign과 verify가 정상적으로 되는지 테스트 해보려고 작성했던 코드이다.
반응형
'안드로이드' 카테고리의 다른 글
[안드로이드] byte Array to String - Base 64를 이용하여 encoding, decoding 시 주의할 점 (JAVA) (0) | 2021.04.30 |
---|---|
[안드로이드] Corutine 이란? (Kotlin) (0) | 2021.02.10 |
[안드로이드] 해시 키 얻어오기 (Kotlin) (0) | 2021.02.09 |
Comments