/// <summary> /// Computes a RSA signature. /// </summary> internal static byte[] Rsa_Sign( ArraySegment <byte> dataToSign, X509Certificate2 signingCertificate, HashAlgorithmName hashAlgorithm, RSASignaturePadding rsaSignaturePadding) { RSA rsa = null; try { // extract the private key. rsa = signingCertificate.GetRSAPrivateKey(); if (rsa == null) { throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No private key for certificate."); } // create the signature. return(rsa.SignData(dataToSign.Array, dataToSign.Offset, dataToSign.Count, hashAlgorithm, rsaSignaturePadding)); } finally { RsaUtils.RSADispose(rsa); } }
/// <summary> /// Verifies a RSA signature. /// </summary> internal static bool Rsa_Verify( ArraySegment <byte> dataToVerify, byte[] signature, X509Certificate2 signingCertificate, HashAlgorithmName hashAlgorithm, RSASignaturePadding rsaSignaturePadding) { RSA rsa = null; try { // extract the public key. rsa = signingCertificate.GetRSAPublicKey(); if (rsa == null) { throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No public key for certificate."); } // verify signature. return(rsa.VerifyData(dataToVerify.Array, dataToVerify.Offset, dataToVerify.Count, signature, hashAlgorithm, rsaSignaturePadding)); } finally { RsaUtils.RSADispose(rsa); } }
/// <summary> /// Create a X509Certificate2 with a private key by combining /// the new certificate with a private key from an existing certificate /// </summary> public static X509Certificate2 CreateCertificateWithPrivateKey( X509Certificate2 certificate, X509Certificate2 certificateWithPrivateKey) { if (!certificateWithPrivateKey.HasPrivateKey) { throw new NotSupportedException("Need a certificate with a private key."); } if (!X509Utils.VerifyRSAKeyPair(certificate, certificateWithPrivateKey)) { throw new NotSupportedException("The public and the private key pair doesn't match."); } string passcode = Guid.NewGuid().ToString(); RSA rsaPrivateKey = null; try { rsaPrivateKey = certificateWithPrivateKey.GetRSAPrivateKey(); byte[] pfxData = CertificateBuilder.CreatePfxWithRSAPrivateKey( certificate, certificate.FriendlyName, rsaPrivateKey, passcode); return(X509Utils.CreateCertificateFromPKCS12(pfxData, passcode)); } finally { RsaUtils.RSADispose(rsaPrivateKey); } }
/// <summary> /// Return the ciphertext block size for RSA OAEP encryption. /// </summary> internal static int GetCipherTextBlockSize(X509Certificate2 encryptingCertificate, Padding padding) { RSA rsa = null; try { rsa = encryptingCertificate.GetRSAPublicKey(); return(GetCipherTextBlockSize(rsa, padding)); } finally { RsaUtils.RSADispose(rsa); } }
/// <summary> /// Returns the size of the public key and disposes RSA key. /// </summary> /// <param name="certificate">The certificate</param> public static int GetRSAPublicKeySize(X509Certificate2 certificate) { RSA rsaPublicKey = null; try { rsaPublicKey = certificate.GetRSAPublicKey(); return(rsaPublicKey.KeySize); } finally { RsaUtils.RSADispose(rsaPublicKey); } }
/// <summary> /// Return the ciphertext block size for RSA OAEP encryption. /// </summary> public static int GetCipherTextBlockSize(X509Certificate2 encryptingCertificate, bool useOaep) { RSA rsa = null; try { rsa = encryptingCertificate.GetRSAPublicKey(); return(GetCipherTextBlockSize(rsa, useOaep)); } finally { RsaUtils.RSADispose(rsa); } }
/// <summary> /// Decrypts the data using RSA encryption. /// </summary> internal static byte[] Decrypt( ArraySegment <byte> dataToDecrypt, X509Certificate2 encryptingCertificate, Padding padding) { RSA rsa = null; try { rsa = encryptingCertificate.GetRSAPrivateKey(); if (rsa == null) { throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No private key for certificate."); } int plainTextSize = dataToDecrypt.Count / GetCipherTextBlockSize(rsa, padding); plainTextSize *= GetPlainTextBlockSize(encryptingCertificate, padding); byte[] buffer = new byte[plainTextSize]; ArraySegment <byte> plainText = Decrypt(dataToDecrypt, rsa, padding, new ArraySegment <byte>(buffer)); System.Diagnostics.Debug.Assert(plainText.Count == buffer.Length); // decode length. int length = 0; length += (((int)plainText.Array[plainText.Offset + 0])); length += (((int)plainText.Array[plainText.Offset + 1]) << 8); length += (((int)plainText.Array[plainText.Offset + 2]) << 16); length += (((int)plainText.Array[plainText.Offset + 3]) << 24); if (length > (plainText.Count - plainText.Offset - 4)) { throw ServiceResultException.Create(StatusCodes.BadEndOfStream, "Could not decrypt data. Invalid total length."); } byte[] decryptedData = new byte[length]; Array.Copy(plainText.Array, plainText.Offset + 4, decryptedData, 0, length); return(decryptedData); } finally { RsaUtils.RSADispose(rsa); } }
/// <summary> /// Returns the length of a RSA PKCS#1 v1.5 signature of a digest. /// </summary> internal static int GetSignatureLength(X509Certificate2 signingCertificate) { RSA rsa = null; try { rsa = signingCertificate.GetRSAPublicKey(); if (rsa == null) { throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No public key for certificate."); } return(rsa.KeySize / 8); } finally { RsaUtils.RSADispose(rsa); } }
/// <summary> /// Encrypts the data using RSA encryption. /// </summary> internal static byte[] Encrypt( byte[] dataToEncrypt, X509Certificate2 encryptingCertificate, Padding padding) { RSA rsa = null; try { rsa = encryptingCertificate.GetRSAPublicKey(); if (rsa == null) { throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No public key for certificate."); } int plaintextBlockSize = GetPlainTextBlockSize(rsa, padding); int blockCount = ((dataToEncrypt.Length + 4) / plaintextBlockSize) + 1; int plainTextSize = blockCount * plaintextBlockSize; int cipherTextSize = blockCount * GetCipherTextBlockSize(rsa, padding); byte[] plainText = new byte[plainTextSize]; // encode length. plainText[0] = (byte)((0x000000FF & dataToEncrypt.Length)); plainText[1] = (byte)((0x0000FF00 & dataToEncrypt.Length) >> 8); plainText[2] = (byte)((0x00FF0000 & dataToEncrypt.Length) >> 16); plainText[3] = (byte)((0xFF000000 & dataToEncrypt.Length) >> 24); // copy data. Array.Copy(dataToEncrypt, 0, plainText, 4, dataToEncrypt.Length); byte[] buffer = new byte[cipherTextSize]; ArraySegment <byte> cipherText = Encrypt(new ArraySegment <byte>(plainText), rsa, padding, new ArraySegment <byte>(buffer)); System.Diagnostics.Debug.Assert(cipherText.Count == buffer.Length); return(buffer); } finally { RsaUtils.RSADispose(rsa); } }