Skip to content

Commit f10502c

Browse files
author
Robot Media
committed
Added custom signature validation support. Closes robotmedia#4
1 parent da715d1 commit f10502c

File tree

1 file changed

+92
-0
lines changed

1 file changed

+92
-0
lines changed
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package net.robotmedia.billing.security;
2+
3+
import java.security.InvalidKeyException;
4+
import java.security.KeyFactory;
5+
import java.security.NoSuchAlgorithmException;
6+
import java.security.PublicKey;
7+
import java.security.Signature;
8+
import java.security.SignatureException;
9+
import java.security.spec.InvalidKeySpecException;
10+
import java.security.spec.X509EncodedKeySpec;
11+
12+
import android.text.TextUtils;
13+
import android.util.Log;
14+
import net.robotmedia.billing.BillingController;
15+
import net.robotmedia.billing.utils.Base64;
16+
import net.robotmedia.billing.utils.Base64DecoderException;
17+
18+
public class DefaultSignatureValidator implements ISignatureValidator {
19+
20+
protected static final String KEY_FACTORY_ALGORITHM = "RSA";
21+
protected static final String SIGNATURE_ALGORITHM = "SHA1withRSA";
22+
23+
/**
24+
* Generates a PublicKey instance from a string containing the
25+
* Base64-encoded public key.
26+
*
27+
* @param encodedPublicKey
28+
* Base64-encoded public key
29+
* @throws IllegalArgumentException
30+
* if encodedPublicKey is invalid
31+
*/
32+
protected PublicKey generatePublicKey(String encodedPublicKey) {
33+
try {
34+
byte[] decodedKey = Base64.decode(encodedPublicKey);
35+
KeyFactory keyFactory = KeyFactory.getInstance(KEY_FACTORY_ALGORITHM);
36+
return keyFactory.generatePublic(new X509EncodedKeySpec(decodedKey));
37+
} catch (NoSuchAlgorithmException e) {
38+
throw new RuntimeException(e);
39+
} catch (InvalidKeySpecException e) {
40+
Log.e(BillingController.LOG_TAG, "Invalid key specification.");
41+
throw new IllegalArgumentException(e);
42+
} catch (Base64DecoderException e) {
43+
Log.e(BillingController.LOG_TAG, "Base64 decoding failed.");
44+
throw new IllegalArgumentException(e);
45+
}
46+
}
47+
48+
private BillingController.IConfiguration configuration;
49+
50+
public DefaultSignatureValidator(BillingController.IConfiguration configuration) {
51+
this.configuration = configuration;
52+
}
53+
54+
protected boolean validate(PublicKey publicKey, String signedData, String signature) {
55+
Signature sig;
56+
try {
57+
sig = Signature.getInstance(SIGNATURE_ALGORITHM);
58+
sig.initVerify(publicKey);
59+
sig.update(signedData.getBytes());
60+
if (!sig.verify(Base64.decode(signature))) {
61+
Log.e(BillingController.LOG_TAG, "Signature verification failed.");
62+
return false;
63+
}
64+
return true;
65+
} catch (NoSuchAlgorithmException e) {
66+
Log.e(BillingController.LOG_TAG, "NoSuchAlgorithmException");
67+
} catch (InvalidKeyException e) {
68+
Log.e(BillingController.LOG_TAG, "Invalid key specification");
69+
} catch (SignatureException e) {
70+
Log.e(BillingController.LOG_TAG, "Signature exception");
71+
} catch (Base64DecoderException e) {
72+
Log.e(BillingController.LOG_TAG, "Base64 decoding failed");
73+
}
74+
return false;
75+
}
76+
77+
@Override
78+
public boolean validate(String signedData, String signature) {
79+
final String publicKey;
80+
if (configuration == null || TextUtils.isEmpty(publicKey = configuration.getPublicKey())) {
81+
Log.w(BillingController.LOG_TAG, "Please set the public key or turn on debug mode");
82+
return false;
83+
}
84+
if (signedData == null) {
85+
Log.e(BillingController.LOG_TAG, "Data is null");
86+
return false;
87+
}
88+
PublicKey key = generatePublicKey(publicKey);
89+
return validate(key, signedData, signature);
90+
}
91+
92+
}

0 commit comments

Comments
 (0)