Search in sources :

Example 1 with RSAPublicKey

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");
    }
}
Also used : ASN1DER(com.mindbright.asn1.ASN1DER) ASN1IA5String(com.mindbright.asn1.ASN1IA5String) RSAPublicKeySpec(java.security.spec.RSAPublicKeySpec) DSAParams(com.mindbright.security.pkcs1.DSAParams) SignatureException(java.security.SignatureException) IOException(java.io.IOException) CertificateException(java.security.cert.CertificateException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) InvalidKeyException(java.security.InvalidKeyException) NoSuchProviderException(java.security.NoSuchProviderException) CertificateEncodingException(java.security.cert.CertificateEncodingException) DSAPublicKey(com.mindbright.security.pkcs1.DSAPublicKey) RSAPublicKey(com.mindbright.security.pkcs1.RSAPublicKey) ByteArrayInputStream(java.io.ByteArrayInputStream) BigInteger(java.math.BigInteger) KeyFactory(java.security.KeyFactory) DSAPublicKeySpec(java.security.spec.DSAPublicKeySpec)

Example 2 with RSAPublicKey

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;
}
Also used : Asn1EncodingException(com.android.apksig.internal.asn1.Asn1EncodingException) RSAPublicKey(com.android.apksig.internal.x509.RSAPublicKey) Asn1DecodingException(com.android.apksig.internal.asn1.Asn1DecodingException) BigInteger(java.math.BigInteger) InvalidKeySpecException(java.security.spec.InvalidKeySpecException) InvalidKeyException(java.security.InvalidKeyException) ByteBuffer(java.nio.ByteBuffer) SubjectPublicKeyInfo(com.android.apksig.internal.x509.SubjectPublicKeyInfo)

Example 3 with RSAPublicKey

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);
}
Also used : SignatureInfo(com.android.apksig.internal.apk.SignatureInfo) ByteBuffer(java.nio.ByteBuffer) SubjectPublicKeyInfo(com.android.apksig.internal.x509.SubjectPublicKeyInfo) SignatureException(java.security.SignatureException) ZipFormatException(com.android.apksig.zip.ZipFormatException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) ApkFormatException(com.android.apksig.apk.ApkFormatException) IOException(java.io.IOException)

Example 4 with RSAPublicKey

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);
}
Also used : RSAPublicKey(com.android.apksig.internal.x509.RSAPublicKey) RandomAccessFile(java.io.RandomAccessFile) File(java.io.File) Test(org.junit.Test)

Aggregations

RSAPublicKey (com.android.apksig.internal.x509.RSAPublicKey)2 SubjectPublicKeyInfo (com.android.apksig.internal.x509.SubjectPublicKeyInfo)2 IOException (java.io.IOException)2 BigInteger (java.math.BigInteger)2 ByteBuffer (java.nio.ByteBuffer)2 InvalidKeyException (java.security.InvalidKeyException)2 NoSuchAlgorithmException (java.security.NoSuchAlgorithmException)2 SignatureException (java.security.SignatureException)2 ApkFormatException (com.android.apksig.apk.ApkFormatException)1 SignatureInfo (com.android.apksig.internal.apk.SignatureInfo)1 Asn1DecodingException (com.android.apksig.internal.asn1.Asn1DecodingException)1 Asn1EncodingException (com.android.apksig.internal.asn1.Asn1EncodingException)1 ZipFormatException (com.android.apksig.zip.ZipFormatException)1 ASN1DER (com.mindbright.asn1.ASN1DER)1 ASN1IA5String (com.mindbright.asn1.ASN1IA5String)1 DSAParams (com.mindbright.security.pkcs1.DSAParams)1 DSAPublicKey (com.mindbright.security.pkcs1.DSAPublicKey)1 RSAPublicKey (com.mindbright.security.pkcs1.RSAPublicKey)1 ByteArrayInputStream (java.io.ByteArrayInputStream)1 File (java.io.File)1