Beispiel #1
0
        private static byte[] GenerateApkSignatureSchemeV2Block(
            SignerConfig signerConfigs,
            IDictionary <ContentDigestAlgorithm, byte[]> contentDigests)
        {
            // FORMAT:
            // * length-prefixed sequence of length-prefixed signer blocks.
            var signerBlocks = new List <byte[]>(1);
            var signerNumber = 0;

            signerNumber++;
            byte[] signerBlock;
            try
            {
                signerBlock = GenerateSignerBlock(signerConfigs, contentDigests);
            }
            catch (CryptographicException e)
            {
                throw new CryptographicException("Signer #" + signerNumber + " failed", e);
            }

            signerBlocks.Add(signerBlock);

            return(EncodeAsSequenceOfLengthPrefixedElements(
                       new[]
            {
                EncodeAsSequenceOfLengthPrefixedElements(signerBlocks),
            }));
        }
Beispiel #2
0
        private static byte[] GenerateApkSigningBlock(SignerConfig signerConfigs,
                                                      IDictionary <ContentDigestAlgorithm, byte[]> contentDigests)
        {
            var apkSignatureSchemeV2Block = GenerateApkSignatureSchemeV2Block(signerConfigs, contentDigests);

            return(GenerateApkSigningBlock(apkSignatureSchemeV2Block));
        }
        /// <summary>
        /// Returns the names of JAR entries which this signer will produce as part of v1 signature.
        /// </summary>
        /// <param name="signerConfig"></param>
        /// <param name="minSdkVersion"></param>
        /// <returns></returns>
        public static ISet <string> GetOutputEntryNames(SignerConfig signerConfig, int minSdkVersion)
        {
            var result     = new HashSet <string>();
            var signerName = signerConfig.Name;

            result.Add("META-INF/" + signerName + ".SF");
            var publicKey = signerConfig.Certificate.PublicKey;
            var signatureBlockFileName =
                "META-INF/" + signerName + ".";

            switch (publicKey.Key)
            {
            case RSACryptoServiceProvider _:
                signatureBlockFileName += "RSA";
                break;

            case DSACryptoServiceProvider _:
                signatureBlockFileName += "DSA";
                break;
            }

            result.Add(signatureBlockFileName);
            result.Add(ManifestEntryName);
            return(result);
        }
        /// <summary>
        /// Signs the provided APK using JAR signing (aka v1 signature scheme) and returns the list of
        /// JAR entries which need to be added to the APK as part of the signature.
        /// </summary>
        /// <param name="signerConfig"></param>
        /// <param name="digestAlgorithm"></param>
        /// <param name="apkSigningSchemeIds"></param>
        /// <param name="manifest"></param>
        /// <returns></returns>
        public static List <Tuple <string, byte[]> > SignManifest(SignerConfig signerConfig,
                                                                  DigestAlgorithm digestAlgorithm, IList <int> apkSigningSchemeIds, OutputManifestFile manifest)
        {
            // For each signer output .SF and .(RSA|DSA|EC) file, then output MANIFEST.MF.
            var signatureJarEntries =
                new List <Tuple <string, byte[]> >(2 * 1 + 1);
            var sfBytes        = GenerateSignatureFile(apkSigningSchemeIds, digestAlgorithm, manifest);
            var signerName     = signerConfig.Name;
            var signatureBlock = GenerateSignatureBlock(signerConfig, sfBytes);

            signatureJarEntries.Add(Tuple.Create("META-INF/" + signerName + ".SF", sfBytes));

            var publicKey = signerConfig.Certificate.PublicKey;
            var signatureBlockFileName =
                "META-INF/" + signerName + ".";

            if (publicKey.Key is RSACryptoServiceProvider)
            {
                signatureBlockFileName += "RSA";
            }
            else if (publicKey.Key is DSACryptoServiceProvider)
            {
                signatureBlockFileName += "DSA";
            }

            signatureJarEntries.Add(
                Tuple.Create(signatureBlockFileName, signatureBlock));
            signatureJarEntries.Add(Tuple.Create(ManifestEntryName, manifest.Contents));
            return(signatureJarEntries);
        }
        /// <summary>
        /// Signs the provided APK using JAR signing (aka v1 signature scheme) and returns the list of
        /// JAR entries which need to be added to the APK as part of the signature.
        /// </summary>
        /// <param name="signerConfig"></param>
        /// <param name="jarEntryDigestAlgorithm"></param>
        /// <param name="jarEntryDigests"></param>
        /// <param name="apkSigningSchemeIds"></param>
        /// <param name="sourceManifestBytes"></param>
        /// <returns></returns>
        public static List <Tuple <string, byte[]> > Sign(SignerConfig signerConfig,
                                                          DigestAlgorithm jarEntryDigestAlgorithm, IDictionary <string, byte[]> jarEntryDigests,
                                                          IList <int> apkSigningSchemeIds, byte[] sourceManifestBytes)
        {
            var manifest =
                GenerateManifestFile(
                    jarEntryDigestAlgorithm, jarEntryDigests, sourceManifestBytes);

            return(SignManifest(
                       signerConfig, jarEntryDigestAlgorithm, apkSigningSchemeIds, manifest));
        }
Beispiel #6
0
        /// <summary>
        /// Signs the provided APK using APK Signature Scheme v2 and returns the APK Signing Block containing the signature.
        /// </summary>
        /// <param name="beforeCentralDir"></param>
        /// <param name="centralDir"></param>
        /// <param name="eocd"></param>
        /// <param name="signerConfig"></param>
        /// <returns></returns>
        public static byte[] GenerateApkSigningBlock(Stream beforeCentralDir, Stream centralDir, Stream eocd,
                                                     SignerConfig signerConfig)
        {
            // Figure out which digest(s) to use for APK contents.
            ISet <ContentDigestAlgorithm> contentDigestAlgorithms = new HashSet <ContentDigestAlgorithm>();

            contentDigestAlgorithms.Add(signerConfig.SignatureAlgorithm.ContentDigestAlgorithm);

            // Ensure that, when digesting, ZIP End of Central Directory record's Central Directory
            // offset field is treated as pointing to the offset at which the APK Signing Block will
            // start.
            var centralDirOffsetForDigesting = beforeCentralDir.Length;
            var eocdBuf = new MemoryStream(new byte[(int)eocd.Length], true);

            eocd.CopyTo(eocdBuf);
            eocdBuf.Position = 0;

            ZipUtils.SetZipEocdCentralDirectoryOffset(eocdBuf, centralDirOffsetForDigesting);

            // Compute digests of APK contents.
            IDictionary <ContentDigestAlgorithm, byte[]> contentDigests; // digest algorithm ID -> digest

            try
            {
                contentDigests =
                    ComputeContentDigests(
                        contentDigestAlgorithms,
                        new[]
                {
                    beforeCentralDir,
                    centralDir,
                    eocdBuf
                });
            }
            catch (IOException e)
            {
                throw new IOException("Failed to read APK being signed", e);
            }
            catch (CryptographicException e)
            {
                throw new CryptographicException("Failed to compute digests of APK", e);
            }

            // Sign the digests and wrap the signatures and signer info into an APK Signing Block.
            return(GenerateApkSigningBlock(signerConfig, contentDigests));
        }
        private static byte[] GenerateSignatureBlock(SignerConfig signerConfig, byte[] signatureFileBytes)
        {
            var signerCert      = signerConfig.Certificate;
            var digestAlgorithm = signerConfig.SignatureDigestAlgorithm;

            var digestAlgorithmId = digestAlgorithm.Oid;

            var content   = new ContentInfo(DataOid, signatureFileBytes);
            var signedCms = new SignedCms(content, true);

            var signer = new CmsSigner(signerCert)
            {
                DigestAlgorithm = digestAlgorithmId
            };

            signedCms.ComputeSignature(signer);

            var encoded = signedCms.Encode();

            return(encoded);
        }
Beispiel #8
0
        private static byte[] GenerateSignerBlock(SignerConfig signerConfig,
                                                  IDictionary <ContentDigestAlgorithm, byte[]> contentDigests)
        {
            var publicKey        = signerConfig.Certificates.PublicKey;
            var encodedPublicKey = EncodePublicKey(publicKey);

            var signedData = new V2SignatureSchemeBlock.SignedData();

            try
            {
                signedData.Certificate = EncodeCertificates(signerConfig.Certificates);
            }
            catch (CryptographicException e)
            {
                throw new CryptographicException("Failed to encode certificates", e);
            }

            var digests = new List <Tuple <int, byte[]> >(1);

            var contentDigestAlgorithm =
                signerConfig.SignatureAlgorithm.ContentDigestAlgorithm;
            var contentDigest = contentDigests[contentDigestAlgorithm];

            if (contentDigest == null)
            {
                throw new Exception(
                          contentDigestAlgorithm + " content digest for " + signerConfig.SignatureAlgorithm
                          + " not computed");
            }

            digests.Add(Tuple.Create(signerConfig.SignatureAlgorithm.Id, contentDigest));
            signedData.Digests = digests;
            var signer = new V2SignatureSchemeBlock.Signer();

            // FORMAT:
            // * length-prefixed sequence of length-prefixed digests:
            //   * uint32: signature algorithm ID
            //   * length-prefixed bytes: digest of contents
            // * length-prefixed sequence of certificates:
            //   * length-prefixed bytes: X.509 certificate (ASN.1 DER encoded).
            // * length-prefixed sequence of length-prefixed additional attributes:
            //   * uint32: ID
            //   * (length - 4) bytes: value
            signer.SignedData = EncodeAsSequenceOfLengthPrefixedElements(new[]
            {
                EncodeAsSequenceOfLengthPrefixedPairsOfIntAndLengthPrefixedBytes(signedData.Digests),
                EncodeAsSequenceOfLengthPrefixedElements(new[] { signedData.Certificate }),
                // additional attributes
                new byte[0],
            });
            signer.PublicKey  = encodedPublicKey;
            signer.Signatures = new List <Tuple <int, byte[]> >(1);
            var signatureAlgorithm = signerConfig.SignatureAlgorithm;

            {
                var    digestAlgorithm = signatureAlgorithm.DigestAlgorithm;
                byte[] signatureBytes;

                var x509Key = new X509AsymmetricSecurityKey(signerConfig.Certificates);

                if (signerConfig.Certificates.PrivateKey is RSACryptoServiceProvider x)
                {
                    if (digestAlgorithm.Oid == DigestAlgorithm.SHA1.Oid)
                    {
                        var rsa = (RSA)x509Key.GetAsymmetricAlgorithm(SecurityAlgorithms.RsaSha1Signature, true);
                        signatureBytes = rsa.SignData(signer.SignedData, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1);
                    }
                    else if (digestAlgorithm.Oid == DigestAlgorithm.SHA256.Oid)
                    {
                        var rsa = (RSA)x509Key.GetAsymmetricAlgorithm(SecurityAlgorithms.RsaSha256Signature, true);
                        signatureBytes = rsa.SignData(signer.SignedData, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
                    }
                    else if (digestAlgorithm.Oid == DigestAlgorithm.SHA512.Oid)
                    {
                        var rsa = (RSA)x509Key.GetAsymmetricAlgorithm("http://www.w3.org/2001/04/xmldsig-more#rsa-sha512", true);
                        signatureBytes = rsa.SignData(signer.SignedData, HashAlgorithmName.SHA512, RSASignaturePadding.Pkcs1);
                    }
                    else
                    {
                        throw new CryptographicException($"Failed to sign using {digestAlgorithm.Name} unsupproted digest");
                    }
                }
                else if (signerConfig.Certificates.PrivateKey is DSACryptoServiceProvider dsa)
                {
                    signatureBytes = dsa.SignData(signer.SignedData);
                }
                else
                {
                    throw new CryptographicException("Failed to sign using " + digestAlgorithm.Name);
                }


                switch (publicKey.Key)
                {
                case RSACryptoServiceProvider rsaPub:
                    using (var rsa2 = new RSACryptoServiceProvider())
                        using (var hash = digestAlgorithm.CreateInstance())
                        {
                            rsa2.ImportParameters(rsaPub.ExportParameters(false));
                            if (!rsa2.VerifyData(signer.SignedData, hash, signatureBytes))
                            {
                                throw new CryptographicException("Signature did not verify");
                            }
                        }

                    break;

                case DSACryptoServiceProvider dsaPub:
                    using (var dsa2 = new DSACryptoServiceProvider())
                    {
                        dsa2.ImportParameters(dsaPub.ExportParameters(false));
                        if (!dsa2.VerifyData(signer.SignedData, signatureBytes))
                        {
                            throw new CryptographicException("Signature did not verify");
                        }
                    }

                    break;

                default:
                    throw new CryptographicException(
                              "Failed to verify generated " + digestAlgorithm.Name + " signature using"
                              + " public key from certificate");
                }

                signer.Signatures.Add(Tuple.Create(signatureAlgorithm.Id, signatureBytes));
            }
            // FORMAT:
            // * length-prefixed signed data
            // * length-prefixed sequence of length-prefixed signatures:
            //   * uint32: signature algorithm ID
            //   * length-prefixed bytes: signature of signed data
            // * length-prefixed bytes: public key (X.509 SubjectPublicKeyInfo, ASN.1 DER encoded)
            return(EncodeAsSequenceOfLengthPrefixedElements(
                       new[]
            {
                signer.SignedData,
                EncodeAsSequenceOfLengthPrefixedPairsOfIntAndLengthPrefixedBytes(
                    signer.Signatures),
                signer.PublicKey,
            }));
        }