Beispiel #1
0
        /// <summary>
        /// Encrypts a blob of data and digitally signs it, returning the resulting JOSE object in compact form.
        /// </summary>
        /// <param name="container"></param>
        /// <param name="data">The data to encrypt and sign.</param>
        /// <param name="encryptFor">Certificate of the recipient. Must contain RSA public key for a 2048-bit key pair or larger.</param>
        /// <param name="signWith">Certificate of the signer. Must be linked to RSA private key at least 2048 bits in length.</param>
        public static string EncryptAndSign(this HelpersContainerClasses.Jose container, byte[] data, X509Certificate2 encryptFor, X509Certificate2 signWith)
        {
            Helpers.Argument.ValidateIsNotNull(data, nameof(data));
            Helpers.Argument.ValidateIsNotNull(encryptFor, nameof(encryptFor));
            Helpers.Argument.ValidateIsNotNull(signWith, nameof(signWith));

            VerifyCertificateIsSaneAndUsable(encryptFor);
            VerifyCertificateAndPrivateKeyIsSaneAndUsable(signWith);

            // Part 1: encrypt.
            var encryptionHeaders = new Dictionary <string, object>
            {
                // Yes, it really is not meant to be base64url for some reason, like the rest of the JOSE object.
                { "x5c", new[] { Convert.ToBase64String(encryptFor.GetRawCertData()) } },
                { "typ", JoseEncryptedType }
            };

            var encrypted = JWT.EncodeBytes(data, encryptFor.GetRSAPublicKey(), JweAlgorithm.RSA_OAEP, JweEncryption.A256CBC_HS512, extraHeaders: encryptionHeaders);

            // Part 2: sign.
            var signingHeaders = new Dictionary <string, object>
            {
                // Yes, it really is not meant to be base64url for some reason, like the rest of the JOSE object.
                { "x5c", new[] { Convert.ToBase64String(signWith.GetRawCertData()) } },
                { "typ", JoseSignedType }
            };

            return(JWT.Encode(encrypted, signWith.GetRSAPrivateKey(), JwsAlgorithm.RS512, extraHeaders: signingHeaders));
        }
Beispiel #2
0
        /// <summary>
        /// Decrypts a blob of data encrypted using <see cref="EncryptAndSign"/> after verifying the digital signature on it.
        /// </summary>
        /// <param name="container"></param>
        /// <param name="joseObject">The compact form of the encrypted and signed JOSE object.</param>
        /// <param name="signedBy">The certificate of the signer will be output into this variable.</param>
        /// <param name="decryptionCertificates">The set of certificates whose key pairs may be used for decryption. The correct certificate and key pair will be selected automatically (if it is among the set).</param>
        /// <exception cref="CryptographicException">
        /// Thrown if a cryptographic operation fails (e.g. because you do not have the correct decryption key).
        /// </exception>
        public static byte[] VerifyAndDecrypt(this HelpersContainerClasses.Jose container, string joseObject, out X509Certificate2 signedBy, params X509Certificate2[] decryptionCertificates)
        {
            Helpers.Argument.ValidateIsNotNull(joseObject, nameof(joseObject));
            Helpers.Argument.ValidateIsNotNull(decryptionCertificates, nameof(decryptionCertificates));

            foreach (var decryptionCertificate in decryptionCertificates)
            {
                if (decryptionCertificate == null)
                {
                    throw new ArgumentException("Decryption certificate list cannot contain null values.", nameof(decryptionCertificates));
                }

                VerifyCertificateAndPrivateKeyIsSaneAndUsable(decryptionCertificate);
            }

            // Part 1: verify signature.
            var signedHeader = JWT.Headers(joseObject);

            if (!signedHeader.ContainsKey("typ") || signedHeader["typ"] as string != JoseSignedType)
            {
                throw new ArgumentException("The JOSE object was not produced by " + nameof(EncryptAndSign), nameof(joseObject));
            }

            signedBy = GetCertificateFromJoseHeader(signedHeader);

            VerifyCertificateIsSaneAndUsable(signedBy);

            var encrypted = JWT.Decode(joseObject, signedBy.GetRSAPublicKey(), JwsAlgorithm.RS512);

            // Part 2: decrypt.
            var encryptedHeader = JWT.Headers(encrypted);

            if (!encryptedHeader.ContainsKey("typ") || encryptedHeader["typ"] as string != JoseEncryptedType)
            {
                throw new ArgumentException("The JOSE object was not produced by " + nameof(EncryptAndSign), nameof(joseObject));
            }

            var encryptedFor = GetCertificateFromJoseHeader(encryptedHeader);

            var decryptWith = decryptionCertificates.FirstOrDefault(c => c.Thumbprint == encryptedFor.Thumbprint);

            if (decryptWith == null)
            {
                throw new CryptographicException("None of the available decryption keys matched the one used to encrypt the JOSE object.");
            }

            return(JWT.DecodeBytes(encrypted, decryptWith.GetRSAPrivateKey(), JweAlgorithm.RSA_OAEP, JweEncryption.A256CBC_HS512));
        }