use of com.android.apksig.internal.x509.RSAPublicKey in project SpringRemote by HaleyWang.
the class X509Certificate method getPublicKey.
public PublicKey getPublicKey() {
SubjectPublicKeyInfo spki = certificate.tbsCertificate.subjectPublicKeyInfo;
String alg = spki.algorithm.algorithmName().toUpperCase();
ASN1DER der = new ASN1DER();
if (alg.startsWith("RSA")) {
RSAPublicKey rsa = new RSAPublicKey();
ByteArrayInputStream ba = new ByteArrayInputStream(spki.subjectPublicKey.getBitArray());
try {
der.decode(ba, rsa);
} catch (Exception e) {
throw new Error("Internal error decoding SubjectPublicKeyInfo.subjectPublicKey: " + e.getMessage());
}
try {
KeyFactory keyFact = KeyFactory.getInstance("RSA");
RSAPublicKeySpec pubSpec = new RSAPublicKeySpec(rsa.modulus.getValue(), rsa.publicExponent.getValue());
return keyFact.generatePublic(pubSpec);
} catch (Exception e) {
throw new Error("Error creating RSA key: " + e.getMessage());
}
} else if (alg.startsWith("DSA")) {
DSAPublicKey dsa = new DSAPublicKey();
ByteArrayInputStream ba = new ByteArrayInputStream(spki.subjectPublicKey.getBitArray());
try {
der.decode(ba, dsa);
} catch (Exception e) {
throw new Error("Internal error decoding SubjectPublicKeyInfo.subjectPublicKey: " + e.getMessage());
}
BigInteger y = dsa.getValue();
DSAParams dsaParams = (DSAParams) spki.algorithm.parameters.getValue();
BigInteger p = dsaParams.p.getValue();
BigInteger q = dsaParams.q.getValue();
BigInteger g = dsaParams.g.getValue();
try {
KeyFactory dsaKeyFact = KeyFactory.getInstance("DSA");
DSAPublicKeySpec dsaPubSpec = new DSAPublicKeySpec(y, p, q, g);
return dsaKeyFact.generatePublic(dsaPubSpec);
} catch (Exception e) {
throw new Error("Error creating DSA key: " + e.getMessage());
}
} else {
throw new Error("Internal error decoding publicKey: unknown algorithm");
}
}
use of com.android.apksig.internal.x509.RSAPublicKey in project apksig by venshine.
the class ApkSigningBlockUtils method encodePublicKey.
public static byte[] encodePublicKey(PublicKey publicKey) throws InvalidKeyException, NoSuchAlgorithmException {
byte[] encodedPublicKey = null;
if ("X.509".equals(publicKey.getFormat())) {
encodedPublicKey = publicKey.getEncoded();
// if the key is an RSA key check for a negative modulus
String keyAlgorithm = publicKey.getAlgorithm();
if ("RSA".equals(keyAlgorithm) || OID_RSA_ENCRYPTION.equals(keyAlgorithm)) {
try {
// Parse the encoded public key into the separate elements of the
// SubjectPublicKeyInfo to obtain the SubjectPublicKey.
ByteBuffer encodedPublicKeyBuffer = ByteBuffer.wrap(encodedPublicKey);
SubjectPublicKeyInfo subjectPublicKeyInfo = Asn1BerParser.parse(encodedPublicKeyBuffer, SubjectPublicKeyInfo.class);
// The SubjectPublicKey is encoded as a bit string within the
// SubjectPublicKeyInfo. The first byte of the encoding is the number of padding
// bits; store this and decode the rest of the bit string into the RSA modulus
// and exponent.
ByteBuffer subjectPublicKeyBuffer = subjectPublicKeyInfo.subjectPublicKey;
byte padding = subjectPublicKeyBuffer.get();
RSAPublicKey rsaPublicKey = Asn1BerParser.parse(subjectPublicKeyBuffer, RSAPublicKey.class);
// byte.
if (rsaPublicKey.modulus.compareTo(BigInteger.ZERO) < 0) {
// A negative modulus indicates the leading bit in the integer is 1. Per
// ASN.1 encoding rules to encode a positive integer with the leading bit
// set to 1 a byte containing all zeros should precede the integer encoding.
byte[] encodedModulus = rsaPublicKey.modulus.toByteArray();
byte[] reencodedModulus = new byte[encodedModulus.length + 1];
reencodedModulus[0] = 0;
System.arraycopy(encodedModulus, 0, reencodedModulus, 1, encodedModulus.length);
rsaPublicKey.modulus = new BigInteger(reencodedModulus);
// Once the modulus has been corrected reencode the RSAPublicKey, then
// restore the padding value in the bit string and reencode the entire
// SubjectPublicKeyInfo to be returned to the caller.
byte[] reencodedRSAPublicKey = Asn1DerEncoder.encode(rsaPublicKey);
byte[] reencodedSubjectPublicKey = new byte[reencodedRSAPublicKey.length + 1];
reencodedSubjectPublicKey[0] = padding;
System.arraycopy(reencodedRSAPublicKey, 0, reencodedSubjectPublicKey, 1, reencodedRSAPublicKey.length);
subjectPublicKeyInfo.subjectPublicKey = ByteBuffer.wrap(reencodedSubjectPublicKey);
encodedPublicKey = Asn1DerEncoder.encode(subjectPublicKeyInfo);
}
} catch (Asn1DecodingException | Asn1EncodingException e) {
System.out.println("Caught a exception encoding the public key: " + e);
e.printStackTrace();
encodedPublicKey = null;
}
}
}
if (encodedPublicKey == null) {
try {
encodedPublicKey = KeyFactory.getInstance(publicKey.getAlgorithm()).getKeySpec(publicKey, X509EncodedKeySpec.class).getEncoded();
} catch (InvalidKeySpecException e) {
throw new InvalidKeyException("Failed to obtain X.509 encoded form of public key " + publicKey + " of class " + publicKey.getClass().getName(), e);
}
}
if ((encodedPublicKey == null) || (encodedPublicKey.length == 0)) {
throw new InvalidKeyException("Failed to obtain X.509 encoded form of public key " + publicKey + " of class " + publicKey.getClass().getName());
}
return encodedPublicKey;
}
use of com.android.apksig.internal.x509.RSAPublicKey in project apksig by venshine.
the class ApkSignerTest method getRSAPublicKeyFromSigningBlock.
private RSAPublicKey getRSAPublicKeyFromSigningBlock(File apk, int signatureVersionId) throws Exception {
int signatureVersionBlockId;
switch(signatureVersionId) {
case ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V2:
signatureVersionBlockId = V2SchemeConstants.APK_SIGNATURE_SCHEME_V2_BLOCK_ID;
break;
case ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V3:
signatureVersionBlockId = V3SchemeConstants.APK_SIGNATURE_SCHEME_V3_BLOCK_ID;
break;
default:
throw new Exception("Invalid signature version ID specified: " + signatureVersionId);
}
SignatureInfo signatureInfo = getSignatureInfoFromApk(apk, signatureVersionId, signatureVersionBlockId);
// FORMAT:
// * length prefixed sequence of length prefixed signers
// * length-prefixed signed data
// * V3+ only - minSDK (uint32)
// * V3+ only - maxSDK (uint32)
// * length-prefixed sequence of length-prefixed signatures:
// * length-prefixed bytes: public key (X.509 SubjectPublicKeyInfo, ASN.1 DER encoded)
ByteBuffer signers = ApkSigningBlockUtils.getLengthPrefixedSlice(signatureInfo.signatureBlock);
ByteBuffer signer = ApkSigningBlockUtils.getLengthPrefixedSlice(signers);
// Since all the data is read from the signer block the signedData and signatures are
// discarded.
ApkSigningBlockUtils.getLengthPrefixedSlice(signer);
// For V3+ signature version IDs discard the min / max SDKs as well
if (signatureVersionId >= ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V3) {
signer.getInt();
signer.getInt();
}
ApkSigningBlockUtils.getLengthPrefixedSlice(signer);
ByteBuffer publicKey = ApkSigningBlockUtils.getLengthPrefixedSlice(signer);
SubjectPublicKeyInfo subjectPublicKeyInfo = Asn1BerParser.parse(publicKey, SubjectPublicKeyInfo.class);
ByteBuffer subjectPublicKeyBuffer = subjectPublicKeyInfo.subjectPublicKey;
// The SubjectPublicKey is stored as a bit string in the SubjectPublicKeyInfo with the first
// byte indicating the number of padding bits in the public key. Read this first byte to
// allow parsing the rest of the RSAPublicKey as a sequence.
subjectPublicKeyBuffer.get();
return Asn1BerParser.parse(subjectPublicKeyBuffer, RSAPublicKey.class);
}
use of com.android.apksig.internal.x509.RSAPublicKey in project apksig by venshine.
the class ApkSignerTest method testPublicKeyHasPositiveModulusAfterSigning.
@Test
public void testPublicKeyHasPositiveModulusAfterSigning() throws Exception {
// The V2 and V3 signature schemes include the public key from the certificate in the
// signing block. If a certificate with an RSAPublicKey is improperly encoded with a
// negative modulus this was previously written to the signing block as is and failed on
// device verification since on device the public key in the certificate was reencoded with
// the correct encoding for the modulus. This test uses an improperly encoded certificate to
// sign an APK and verifies that the public key in the signing block is corrected with a
// positive modulus to allow on device installs / updates.
List<ApkSigner.SignerConfig> signersList = Collections.singletonList(getDefaultSignerConfigFromResources(FIRST_RSA_2048_SIGNER_RESOURCE_NAME, FIRST_RSA_2048_SIGNER_CERT_WITH_NEGATIVE_MODULUS));
File signedApk = sign("original.apk", new ApkSigner.Builder(signersList).setV1SigningEnabled(true).setV2SigningEnabled(true).setV3SigningEnabled(true));
RSAPublicKey v2PublicKey = getRSAPublicKeyFromSigningBlock(signedApk, ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V2);
assertTrue("The modulus in the public key in the V2 signing block must not be negative", v2PublicKey.modulus.compareTo(BigInteger.ZERO) > 0);
RSAPublicKey v3PublicKey = getRSAPublicKeyFromSigningBlock(signedApk, ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V3);
assertTrue("The modulus in the public key in the V3 signing block must not be negative", v3PublicKey.modulus.compareTo(BigInteger.ZERO) > 0);
}
Aggregations