Beispiel #1
0
        private static ReadOnlySpan <byte> GetOctetStringContents(
            ReadOnlySpan <byte> source,
            AsnEncodingRules ruleSet,
            Asn1Tag expectedTag,
            UniversalTagNumber universalTagNumber,
            out int bytesConsumed,
            ref byte[]?rented,
            Span <byte> tmpSpace = default)
        {
            Debug.Assert(rented == null);

            if (TryReadPrimitiveOctetStringCore(
                    source,
                    ruleSet,
                    expectedTag,
                    universalTagNumber,
                    out int?contentLength,
                    out int headerLength,
                    out ReadOnlySpan <byte> contents,
                    out bytesConsumed))
            {
                return(contents);
            }

            // If we get here, the tag was appropriate, but the encoding was constructed.

            // Guaranteed long enough
            contents = source.Slice(headerLength);
            int tooBig = contentLength ?? SeekEndOfContents(contents, ruleSet);

            if (tmpSpace.Length > 0 && tooBig > tmpSpace.Length)
            {
                bool isIndefinite = contentLength == null;
                tooBig = CountConstructedOctetString(contents, ruleSet, isIndefinite);
            }

            if (tooBig > tmpSpace.Length)
            {
                rented   = CryptoPool.Rent(tooBig);
                tmpSpace = rented;
            }

            if (TryCopyConstructedOctetStringContents(
                    Slice(source, headerLength, contentLength),
                    ruleSet,
                    tmpSpace,
                    contentLength == null,
                    out int bytesRead,
                    out int bytesWritten))
            {
                bytesConsumed = headerLength + bytesRead;
                return(tmpSpace.Slice(0, bytesWritten));
            }

            Debug.Fail("TryCopyConstructedOctetStringContents failed with a pre-allocated buffer");
            throw new AsnContentException();
        }
Beispiel #2
0
        internal static ReadOnlyMemory <byte> GetContent(
            ReadOnlyMemory <byte> wrappedContent,
            string contentType)
        {
            // Read the input.
            //
            // PKCS7's id-data is written in both PKCS#7 and CMS as an OCTET STRING wrapping
            // the arbitrary bytes, so the OCTET STRING must always be present.
            //
            // For other types, CMS says to always write an OCTET STRING, and to put the properly
            // encoded data within it.
            // PKCS#7 originally ommitted the OCTET STRING wrapper for this model, so this is the
            // dynamic adapter.
            //
            // See https://tools.ietf.org/html/rfc5652#section-5.2.1
            byte[]? rented = null;
            int bytesWritten = 0;

            try
            {
                AsnReader reader = new AsnReader(wrappedContent, AsnEncodingRules.BER);

                if (reader.TryReadPrimitiveOctetString(out ReadOnlyMemory <byte> inner))
                {
                    return(inner);
                }

                rented = CryptoPool.Rent(wrappedContent.Length);

                if (!reader.TryReadOctetString(rented, out bytesWritten))
                {
                    Debug.Fail($"TryCopyOctetStringBytes failed with an array larger than the encoded value");
                    throw new CryptographicException();
                }

                return(rented.AsSpan(0, bytesWritten).ToArray());
            }
            catch (Exception) when(contentType != Oids.Pkcs7Data)
            {
            }
            catch (AsnContentException e)
            {
                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e);
            }
            finally
            {
                if (rented != null)
                {
                    CryptoPool.Return(rented, bytesWritten);
                }
            }

            // PKCS#7 encoding for something other than id-data.
            Debug.Assert(contentType != Oids.Pkcs7Data);
            return(wrappedContent);
        }
        private static byte[]? DecryptKey(
            RSA?privateKey,
            RSAEncryptionPadding encryptionPadding,
            ReadOnlySpan <byte> encryptedKey,
            out Exception?exception)
        {
            if (privateKey == null)
            {
                exception = new CryptographicException(SR.Cryptography_Cms_Signing_RequiresPrivateKey);
                return(null);
            }

#if NETCOREAPP || NETSTANDARD2_1
            byte[]? cek = null;
            int cekLength = 0;

            try
            {
                cek = CryptoPool.Rent(privateKey.KeySize / 8);

                if (!privateKey.TryDecrypt(encryptedKey, cek, encryptionPadding, out cekLength))
                {
                    Debug.Fail("TryDecrypt wanted more space than the key size");
                    exception = new CryptographicException();
                    return(null);
                }

                exception = null;
                return(new Span <byte>(cek, 0, cekLength).ToArray());
            }
            catch (CryptographicException e)
            {
                exception = e;
                return(null);
            }
            finally
            {
                if (cek != null)
                {
                    CryptoPool.Return(cek, cekLength);
                }
            }
#else
            try
            {
                exception = null;
                return(privateKey.Decrypt(encryptedKey.ToArray(), encryptionPadding));
            }
            catch (CryptographicException e)
            {
                exception = e;
                return(null);
            }
#endif
        }
Beispiel #4
0
        /// <summary>
        /// Return a copy of the passed in secret key, encrypted using a new password
        /// and the passed in algorithm.
        /// </summary>
        /// <remarks>
        /// Allows the caller to handle the encoding of the passphrase to bytes.
        /// </remarks>
        /// <param name="key">The PgpSecretKey to be copied.</param>
        /// <param name="rawOldPassPhrase">The current password for the key.</param>
        /// <param name="rawNewPassPhrase">The new password for the key.</param>
        public static PgpSecretKey CopyWithNewPassword(
            PgpSecretKey key,
            ReadOnlySpan <byte> rawOldPassPhrase,
            ReadOnlySpan <byte> rawNewPassPhrase)
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }
            if (key.IsPrivateKeyEmpty)
            {
                throw new PgpException("no private key in this SecretKey - public key present only.");
            }

            byte[] rawKeyData = CryptoPool.Rent(key.keyPacket.KeyBytes.Length - key.keyPacket.PublicKeyLength + 0x20);
            try
            {
                S2kBasedEncryption.DecryptSecretKey(
                    rawOldPassPhrase,
                    key.keyPacket.KeyBytes.AsSpan(key.keyPacket.PublicKeyLength),
                    rawKeyData,
                    out int rawKeySize,
                    key.keyPacket.Version);

                // Use the default S2K parameters
                var s2kParameters = new S2kParameters();

                var newKeyData = new byte[S2kBasedEncryption.GetEncryptedLength(s2kParameters, rawKeySize, key.keyPacket.Version) + key.keyPacket.PublicKeyLength];
                key.keyPacket.KeyBytes.AsSpan(0, key.keyPacket.PublicKeyLength).CopyTo(newKeyData);

                S2kBasedEncryption.EncryptSecretKey(
                    rawNewPassPhrase,
                    s2kParameters,
                    rawKeyData.AsSpan(0, rawKeySize),
                    newKeyData.AsSpan(key.keyPacket.PublicKeyLength),
                    key.keyPacket.Version);

                SecretKeyPacket newKeyPacket;
                if (key.keyPacket is SecretSubkeyPacket)
                {
                    newKeyPacket = new SecretSubkeyPacket(key.Algorithm, key.CreationTime, newKeyData);
                }
                else
                {
                    newKeyPacket = new SecretKeyPacket(key.Algorithm, key.CreationTime, newKeyData);
                }

                return(new PgpSecretKey(newKeyPacket, key));
            }
            finally
            {
                CryptoPool.Return(rawKeyData);
            }
        }
Beispiel #5
0
            private static byte[]? DecryptContent(
                ReadOnlyMemory <byte> encryptedContent,
                byte[] cek,
                AlgorithmIdentifierAsn contentEncryptionAlgorithm,
                out Exception?exception)
            {
                exception = null;
                int encryptedContentLength = encryptedContent.Length;

                byte[]? encryptedContentArray = CryptoPool.Rent(encryptedContentLength);

                try
                {
                    encryptedContent.CopyTo(encryptedContentArray);

                    using (SymmetricAlgorithm alg = OpenAlgorithm(contentEncryptionAlgorithm))
                    {
                        ICryptoTransform decryptor;

                        try
                        {
                            decryptor = alg.CreateDecryptor(cek, alg.IV);
                        }
                        catch (ArgumentException ae)
                        {
                            // Decrypting or deriving the symmetric key with the wrong key may still succeed
                            // but produce a symmetric key that is not the correct length.
                            throw new CryptographicException(SR.Cryptography_Cms_InvalidSymmetricKey, ae);
                        }

                        using (decryptor)
                        {
                            // If we extend this library to accept additional algorithm providers
                            // then a different array pool needs to be used.
                            Debug.Assert(alg.GetType().Assembly == typeof(Aes).Assembly);

                            return(decryptor.OneShot(
                                       encryptedContentArray,
                                       0,
                                       encryptedContentLength));
                        }
                    }
                }
                catch (CryptographicException e)
                {
                    exception = e;
                    return(null);
                }
                finally
                {
                    CryptoPool.Return(encryptedContentArray, encryptedContentLength);
                    encryptedContentArray = null;
                }
            }
Beispiel #6
0
        private static void SortContents(byte[] buffer, int start, int end)
        {
            Debug.Assert(buffer != null);
            Debug.Assert(end >= start);

            int len = end - start;

            if (len == 0)
            {
                return;
            }

            // Since BER can read everything and the reader does not mutate data
            // just use a BER reader for identifying the positions of the values
            // within this memory segment.
            //
            // Since it's not mutating, any restrictions imposed by CER or DER will
            // still be maintained.
            var reader = new AsnReader(new ReadOnlyMemory <byte>(buffer, start, len), AsnEncodingRules.BER);

            List <(int, int)> positions = new List <(int, int)>();

            int pos = start;

            while (reader.HasData)
            {
                ReadOnlyMemory <byte> encoded = reader.ReadEncodedValue();
                positions.Add((pos, encoded.Length));
                pos += encoded.Length;
            }

            Debug.Assert(pos == end);

            var comparer = new ArrayIndexSetOfValueComparer(buffer);

            positions.Sort(comparer);

            byte[] tmp = CryptoPool.Rent(len);

            pos = 0;

            foreach ((int offset, int length) in positions)
            {
                Buffer.BlockCopy(buffer, offset, tmp, pos, length);
                pos += length;
            }

            Debug.Assert(pos == len);

            Buffer.BlockCopy(tmp, 0, buffer, start, len);
            CryptoPool.Return(tmp, len);
        }
        public TailEndCryptoTransform(ICryptoTransform innerTransform, int tailEndSize)
        {
            int rollingBufferSize =
                innerTransform.CanTransformMultipleBlocks ?
                128 * innerTransform.InputBlockSize :
                innerTransform.InputBlockSize +
                tailEndSize;

            this.innerTransform      = innerTransform;
            this.tailEndSize         = tailEndSize;
            this.rollingBuffer       = new ArraySegment <byte>(CryptoPool.Rent(rollingBufferSize), 0, rollingBufferSize);
            this.rollingBufferOffset = 0;
        }
 /// <summary>Add a PBE encryption method to the encrypted object.</summary>
 public void AddMethod(ReadOnlySpan <char> passPhrase, PgpHashAlgorithm s2kDigest)
 {
     byte[] rawPassPhrase = Array.Empty <byte>();
     try
     {
         rawPassPhrase = CryptoPool.Rent(Encoding.UTF8.GetByteCount(passPhrase));
         int bytesWritten = Encoding.UTF8.GetBytes(passPhrase, rawPassPhrase);
         AddMethod(rawPassPhrase.AsSpan(0, bytesWritten), s2kDigest);
     }
     finally
     {
         CryptoPool.Return(rawPassPhrase);
     }
 }
Beispiel #9
0
        public static byte[] DecodeOctetStringCore(byte[] encodedOctets)
        {
            // Read using BER because the CMS specification says the encoding is BER.
            AsnReader reader = new AsnReader(encodedOctets, AsnEncodingRules.BER);

            const int   ArbitraryStackLimit = 256;
            Span <byte> tmp = stackalloc byte[ArbitraryStackLimit];
            // Use stackalloc 0 so data can later hold a slice of tmp.
            ReadOnlySpan <byte> data = stackalloc byte[0];

            byte[] poolBytes = null;

            try
            {
                if (!reader.TryReadPrimitiveOctetStringBytes(out var contents))
                {
                    if (reader.TryCopyOctetStringBytes(tmp, out int bytesWritten))
                    {
                        data = tmp.Slice(0, bytesWritten);
                    }
                    else
                    {
                        poolBytes = CryptoPool.Rent(reader.PeekContentBytes().Length);

                        if (!reader.TryCopyOctetStringBytes(poolBytes, out bytesWritten))
                        {
                            Debug.Fail("TryCopyOctetStringBytes failed with a provably-large-enough buffer");
                            throw new CryptographicException();
                        }

                        data = new ReadOnlySpan <byte>(poolBytes, 0, bytesWritten);
                    }
                }
                else
                {
                    data = contents.Span;
                }

                reader.ThrowIfNotEmpty();

                return(data.ToArray());
            }
            finally
            {
                if (poolBytes != null)
                {
                    CryptoPool.Return(poolBytes, data.Length);
                }
            }
        }
Beispiel #10
0
        public void Encrypt(ReadOnlySpan <byte> nonce, ReadOnlySpan <byte> plaintext, Span <byte> ciphertext, Span <byte> tag, ReadOnlySpan <byte> associatedData = default)
        {
            CheckParameters(plaintext, ciphertext, nonce, tag);

            var realNonce = CryptoPool.Rent(16);
            var stretch   = CryptoPool.Rent(24);
            var offset    = CryptoPool.Rent(16);
            var checksum  = CryptoPool.Rent(16);
            var tmp       = CryptoPool.Rent(16);

            CryptographicOperations.ZeroMemory(checksum.AsSpan(0, 16));

            try
            {
                int bottom = nonce[^ 1] & 0x3f;
Beispiel #11
0
        public AesOcb(ReadOnlySpan <byte> key)
        {
            this.aes         = Aes.Create();
            this.aes.Key     = key.ToArray();
            this.aes.Mode    = CipherMode.ECB;
            this.aes.Padding = PaddingMode.None;

            l_star   = CryptoPool.Rent(16);
            l_dollar = CryptoPool.Rent(16);

            encryptor = aes.CreateEncryptor();
            CryptographicOperations.ZeroMemory(l_star.AsSpan(0, 16));
            encryptor.TransformBlock(l_star, 0, 16, l_star, 0);
            Double(l_star, l_dollar);
        }
Beispiel #12
0
        private static unsafe string HexDump(byte *bytes, uint length, int bytesPerLine = 16)
        {
            var lengthInt = (int)length;

            using (var pool = CryptoPool.Rent <byte>(lengthInt))
            {
                var managedBytes = pool.Memory.Slice(0, lengthInt);

                var span = new Span <byte>(bytes, lengthInt);

                span.CopyTo(managedBytes.Span);

                return(HexDump(managedBytes.Span, bytesPerLine));
            }
        }
        private unsafe DiffieHellmanKey ExportKey(string keyType, DateTimeOffset?expiry)
        {
            int status = 0;

            status = BCryptExportKey(hPrivateKey, IntPtr.Zero, keyType, null, 0, out int pcbResult, 0);

            ThrowIfNotNtSuccess(status);

            DiffieHellmanKey key;

            using (var rental = CryptoPool.Rent <byte>(pcbResult))
            {
                var output = rental.Memory;

                fixed(byte *pbOutput = &MemoryMarshal.GetReference(output.Span))
                {
                    status = BCryptExportKey(hPrivateKey, IntPtr.Zero, keyType, pbOutput, pcbResult, out pcbResult, 0);

                    ThrowIfNotNtSuccess(status);

                    BCRYPT_DH_KEY_BLOB *param = (BCRYPT_DH_KEY_BLOB *)pbOutput;

                    key = new DiffieHellmanKey()
                    {
                        KeyLength   = param->header.cbKey,
                        Algorithm   = param->header.cbKey < 256 ? KeyAgreementAlgorithm.DiffieHellmanModp2 : KeyAgreementAlgorithm.DiffieHellmanModp14,
                        Type        = param->header.dwMagic == BCRYPT_DH_PRIVATE_MAGIC ? AsymmetricKeyType.Private : AsymmetricKeyType.Public,
                        CacheExpiry = expiry
                    };
                }

                var export = output.Span.Slice(sizeof(BCRYPT_DH_KEY_BLOB_HEADER));

                key.Modulus   = Copy(export.Slice(0, key.KeyLength));
                key.Generator = Copy(export.Slice(key.KeyLength, key.KeyLength));
                key.Public    = Copy(export.Slice(key.KeyLength + key.KeyLength, key.KeyLength));

                if (key.Type == AsymmetricKeyType.Private)
                {
                    key.Private = Copy(export.Slice(key.KeyLength + key.KeyLength + key.KeyLength, key.KeyLength));
                }

                key.Factor = Copy(Factor);
            }

            return(key);
        }
Beispiel #14
0
        public static ReadOnlyMemory <byte> Decrypt(
            ReadOnlyMemory <byte> ciphertext,
            ReadOnlyMemory <byte> key,
            ReadOnlyMemory <byte> iv
            )
        {
            if (!CalculateLength(ciphertext.Length, out int padSize, out int maxLength))
            {
                return(ciphertext);
            }

            using (var rental = CryptoPool.Rent <byte>(maxLength))
            {
                var aes = CryptoPal.Platform.Aes();

                Memory <byte> ciphertextRented;

                if (padSize == BlockSize)
                {
                    ciphertextRented = rental.Memory.Slice(0, ciphertext.Length);

                    ciphertext.CopyTo(ciphertextRented);
                }
                else
                {
                    var depadded = Depad(ciphertext, padSize);

                    var decryptedPad = aes.Decrypt(depadded, key, iv);

                    ciphertextRented = rental.Memory.Slice(0, maxLength);

                    ciphertext.CopyTo(ciphertextRented);

                    decryptedPad.Slice(decryptedPad.Length - padSize)
                    .CopyTo(
                        ciphertextRented.Slice(ciphertext.Length)
                        );
                }

                if (ciphertext.Length >= TwoBlockSizes)
                {
                    SwapLastTwoBlocks(ciphertextRented.Span);
                }

                return(aes.Decrypt(ciphertextRented, key, iv).Slice(0, ciphertext.Length));
            }
        }
        private void WriteConstructedCerCharacterString(Asn1Tag tag, Text.Encoding encoding, ReadOnlySpan <char> str, int size)
        {
            Debug.Assert(size > AsnReader.MaxCERSegmentSize);

            byte[] tmp     = CryptoPool.Rent(size);
            int    written = encoding.GetBytes(str, tmp);

            if (written != size)
            {
                Debug.Fail(
                    $"Encoding produced different answer for GetByteCount ({size}) and GetBytes ({written})");
                throw new InvalidOperationException();
            }

            WriteConstructedCerOctetString(tag, tmp.AsSpan(0, size));
            CryptoPool.Return(tmp, size);
        }
Beispiel #16
0
        /// <summary>
        ///   Reads a NamedBitList from <paramref name="source"/> with a specified tag under
        ///   the specified encoding rules.
        /// </summary>
        /// <param name="source">The buffer containing encoded data.</param>
        /// <param name="ruleSet">The encoding constraints to use when interpreting the data.</param>
        /// <param name="bytesConsumed">
        ///   When this method returns, the total number of bytes for the encoded value.
        ///   This parameter is treated as uninitialized.
        /// </param>
        /// <param name="expectedTag">
        ///   The tag to check for before reading, or <see langword="null"/> for the default tag (Universal 3).
        /// </param>
        /// <returns>
        ///   The bits from the encoded value.
        /// </returns>
        /// <exception cref="ArgumentOutOfRangeException">
        ///   <paramref name="ruleSet"/> is not defined.
        /// </exception>
        /// <exception cref="AsnContentException">
        ///   the next value does not have the correct tag.
        ///
        ///   -or-
        ///
        ///   the length encoding is not valid under the current encoding rules.
        ///
        ///   -or-
        ///
        ///   the contents are not valid under the current encoding rules.
        /// </exception>
        /// <exception cref="ArgumentException">
        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
        ///   <see cref="TagClass.Universal"/>, but
        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
        ///   the method.
        /// </exception>
        /// <remarks>
        ///   The bit alignment performed by this method is to interpret the most significant bit
        ///   in the first byte of the value as bit 0,
        ///   with bits increasing in value until the least significant bit of the first byte, proceeding
        ///   with the most significant bit of the second byte, and so on.
        ///   This means that the number used in an ASN.1 NamedBitList construction is the index in the
        ///   return value.
        /// </remarks>
        public static BitArray ReadNamedBitList(
            ReadOnlySpan <byte> source,
            AsnEncodingRules ruleSet,
            out int bytesConsumed,
            Asn1Tag?expectedTag = null)
        {
            Asn1Tag actualTag = ReadEncodedValue(source, ruleSet, out _, out int contentLength, out _);

            // Get the last ArgumentException out of the way before we rent arrays
            if (expectedTag != null)
            {
                CheckExpectedTag(actualTag, expectedTag.Value, UniversalTagNumber.BitString);
            }

            // The number of interpreted bytes is at most contentLength - 1, just ask for contentLength.
            byte[] rented = CryptoPool.Rent(contentLength);

            if (!TryReadBitString(
                    source,
                    rented,
                    ruleSet,
                    out int unusedBitCount,
                    out int consumed,
                    out int written,
                    expectedTag))
            {
                Debug.Fail("TryReadBitString failed with an over-allocated buffer");
                throw new InvalidOperationException();
            }

            int validBitCount = checked (written * 8 - unusedBitCount);

            Span <byte> valueSpan = rented.AsSpan(0, written);

            ReverseBitsPerByte(valueSpan);

            BitArray ret = new BitArray(rented);

            CryptoPool.Return(rented, written);

            // Trim off all of the unnecessary parts.
            ret.Length = validBitCount;

            bytesConsumed = consumed;
            return(ret);
        }
        private ReadOnlySpan <byte> GetOctetStringContents(
            Asn1Tag expectedTag,
            UniversalTagNumber universalTagNumber,
            out int bytesRead,
            ref byte[]?rented,
            Span <byte> tmpSpace = default)
        {
            Debug.Assert(rented == null);

            if (TryReadPrimitiveOctetStringBytes(
                    expectedTag,
                    out Asn1Tag actualTag,
                    out int?contentLength,
                    out int headerLength,
                    out ReadOnlySpan <byte> contentsOctets,
                    universalTagNumber))
            {
                bytesRead = headerLength + contentsOctets.Length;
                return(contentsOctets);
            }

            Debug.Assert(actualTag.IsConstructed);

            ReadOnlySpan <byte> source = Slice(_data, headerLength, contentLength);
            bool isIndefinite          = contentLength == null;
            int  octetStringLength     = CountConstructedOctetString(source, isIndefinite);

            if (tmpSpace.Length < octetStringLength)
            {
                rented   = CryptoPool.Rent(octetStringLength);
                tmpSpace = rented;
            }

            CopyConstructedOctetString(
                source,
                tmpSpace,
                isIndefinite,
                out int localBytesRead,
                out int bytesWritten);

            Debug.Assert(bytesWritten == octetStringLength);

            bytesRead = headerLength + localBytesRead;
            return(tmpSpace.Slice(0, bytesWritten));
        }
        public override ReadOnlyMemory <byte> Encrypt(ReadOnlyMemory <byte> data, KerberosKey kerberosKey, KeyUsage usage)
        {
            var ke = this.GetOrDeriveKey(kerberosKey, usage, KeyDerivationMode.Ke);

            ReadOnlyMemory <byte> confounder;

            if (this.Confounder.Length > 0)
            {
                confounder = this.Confounder;
            }
            else
            {
                confounder = this.GenerateRandomBytes(this.ConfounderSize);
            }

            var concatLength = confounder.Length + data.Length;

            using (var cleartextPool = CryptoPool.Rent <byte>(concatLength))
            {
                var cleartext = cleartextPool.Memory.Slice(0, concatLength);

                Concat(confounder.Span, data.Span, cleartext);

                var encrypted = AESCTS.Encrypt(
                    cleartext,
                    ke,
                    AllZerosInitVector
                    );

                var checksumDataLength = AllZerosInitVector.Length + encrypted.Length;

                using (var checksumDataRented = CryptoPool.Rent <byte>(checksumDataLength))
                {
                    var checksumData = checksumDataRented.Memory.Slice(0, checksumDataLength);

                    Concat(AllZerosInitVector.Span, encrypted.Span, checksumData);

                    var checksum = this.MakeChecksum(checksumData, kerberosKey, usage, KeyDerivationMode.Ki, this.ChecksumSize);

                    return(Concat(encrypted.Span, checksum.Span));
                }
            }
        }
Beispiel #19
0
        /// <summary>
        /// Builds an <see cref="X500DistinguishedName" /> that represents the encoded attributes.
        /// </summary>
        /// <returns>
        /// An <see cref="X500DistinguishedName" /> that represents the encoded attributes.
        /// </returns>
        public X500DistinguishedName Build()
        {
            _writer.Reset();

            using (_writer.PushSequence())
            {
                for (int i = _encodedComponents.Count - 1; i >= 0; i--)
                {
                    _writer.WriteEncodedValue(_encodedComponents[i]);
                }
            }

            byte[] rented              = CryptoPool.Rent(_writer.GetEncodedLength());
            int    encoded             = _writer.Encode(rented);
            X500DistinguishedName name = new X500DistinguishedName(rented.AsSpan(0, encoded));

            CryptoPool.Return(rented, clearSize: 0); // Distinguished Names do not contain sensitive information.
            return(name);
        }
Beispiel #20
0
        public CFBMode(byte[] iv, IBlockTransform blockTransform, bool encryption, int paddingSizeInBytes)
            : base(iv, blockTransform.BlockSizeInBytes, paddingSizeInBytes)
        {
            if (iv == null)
            {
                throw new ArgumentNullException(nameof(iv));
            }
            if (iv.Length != blockTransform.BlockSizeInBytes)
            {
                throw new ArgumentOutOfRangeException(nameof(iv));
            }

            this.FR  = CryptoPool.Rent(iv.Length);
            this.FRE = CryptoPool.Rent(iv.Length);
            iv.CopyTo(this.FR, 0);

            this.blockTransform = blockTransform;
            this.encryption     = encryption;
        }
Beispiel #21
0
        public byte[] ExportPrivateKey(
            ReadOnlySpan <byte> passwordBytes,
            S2kParameters s2kParameters)
        {
            ECParameters ecParameters = new ECParameters();

            byte[] secretPart = Array.Empty <byte>();

            try
            {
                ecParameters = ecdh.ExportParameters(true);
                if (ecdh is X25519)
                {
                    Array.Reverse(ecParameters.D !);
                }

                int secretSize = MPInteger.GetMPEncodedLength(ecParameters.D !);
                secretPart = CryptoPool.Rent(secretSize);
                MPInteger.TryWriteInteger(ecParameters.D, secretPart, out var _);

                int encryptedSecretLength = S2kBasedEncryption.GetEncryptedLength(s2kParameters, secretSize);
                int estimatedLength       =
                    32 /* OID */ +
                    MPInteger.GetMPEncodedLength(ecParameters.Q.X !, ecParameters.Q.Y !) + 1 /* EC Point type */ +
                    4 /* KDF Parameters */ +
                    encryptedSecretLength;
                var destination = new byte[estimatedLength];
                WriteOpenPgpECParameters(ecParameters, destination, out int bytesWritten);
                WriteKDFParameters(destination.AsSpan(bytesWritten));

                S2kBasedEncryption.EncryptSecretKey(passwordBytes, s2kParameters, secretPart.AsSpan(0, secretSize), destination.AsSpan(bytesWritten + 4));
                return(destination.AsSpan(0, bytesWritten + 4 + encryptedSecretLength).ToArray());
            }
            finally
            {
                CryptoPool.Return(secretPart);
                if (ecParameters.D != null)
                {
                    CryptographicOperations.ZeroMemory(ecParameters.D);
                }
            }
        }
        protected override ReadOnlyMemory <byte> String2Key(ReadOnlyMemory <byte> password, ReadOnlyMemory <byte> salt, ReadOnlyMemory <byte> param)
        {
            /*
             * iter_count = string-to-key parameter, default is decimal 32768
             * saltp = enctype-name | 0x00 | salt
             * tkey = random-to-key(PBKDF2(passphrase, saltp, iter_count, keylength))
             * base-key = random-to-key(KDF-HMAC-SHA2(tkey, "kerberos", keylength))
             *
             * where "kerberos" is the octet-string 0x6B65726265726F73.
             */

            var encLength = this.encTypeNameBytes.Length;

            var saltpLen = encLength + 1 + salt.Length;

            using (var saltpRented = CryptoPool.Rent <byte>(saltpLen))
            {
                var saltp = saltpRented.Memory.Slice(0, saltpLen);

                this.encTypeNameBytes.CopyTo(saltp);

                salt.CopyTo(saltp.Slice(encLength + 1));

                var iterationsLen = param.Length == 0 ? 4 : param.Length;

                using (var iterationsRented = CryptoPool.Rent <byte>(iterationsLen))
                {
                    var iterations = iterationsRented.Memory.Slice(0, iterationsLen);

                    if (param.Length == 0)
                    {
                        DefaultIterations.CopyTo(iterations);
                    }
                    else
                    {
                        param.CopyTo(iterations);
                    }

                    return(base.String2Key(password, saltp, iterations));
                }
            }
        }
Beispiel #23
0
        /// <summary>
        /// Return a copy of the passed in secret key, encrypted using a new password
        /// and the passed in algorithm.
        /// </summary>
        /// <param name="key">The PgpSecretKey to be copied.</param>
        /// <param name="oldPassPhrase">The current password for the key.</param>
        /// <param name="newPassPhrase">The new password for the key.</param>
        public static PgpSecretKey CopyWithNewPassword(
            PgpSecretKey key,
            ReadOnlySpan <char> oldPassPhrase,
            ReadOnlySpan <char> newPassPhrase)
        {
            int oldPassPhraseByteCount = Encoding.UTF8.GetByteCount(oldPassPhrase);
            int newPassPhraseByteCount = Encoding.UTF8.GetByteCount(newPassPhrase);

            byte[] passphraseBuffer = CryptoPool.Rent(oldPassPhraseByteCount + newPassPhraseByteCount);
            try
            {
                Encoding.UTF8.GetBytes(oldPassPhrase, passphraseBuffer);
                Encoding.UTF8.GetBytes(newPassPhrase, passphraseBuffer.AsSpan(oldPassPhraseByteCount));
                return(CopyWithNewPassword(key, passphraseBuffer.AsSpan(0, oldPassPhraseByteCount), passphraseBuffer.AsSpan(oldPassPhraseByteCount, newPassPhraseByteCount)));
            }
            finally
            {
                CryptoPool.Return(passphraseBuffer, oldPassPhraseByteCount + newPassPhraseByteCount);
            }
        }
Beispiel #24
0
        private static ArraySegment <byte> EncodeKeys(AsnWriter tmpWriter, SafeBagAsn[] keyBags, int keyCount)
        {
            Debug.Assert(tmpWriter.GetEncodedLength() == 0);
            tmpWriter.PushSequence();

            for (int i = 0; i < keyCount; i++)
            {
                keyBags[i].Encode(tmpWriter);
            }

            tmpWriter.PopSequence();
            ReadOnlySpan <byte> encodedKeys = tmpWriter.EncodeAsSpan();
            int length = encodedKeys.Length;

            byte[] keyBuf = CryptoPool.Rent(length);
            encodedKeys.CopyTo(keyBuf);
            tmpWriter.Reset();

            return(new ArraySegment <byte>(keyBuf, 0, length));
        }
Beispiel #25
0
        private static string GetStringProvParam(
            SafeProvOrNCryptKeyHandle handle,
            CryptProvParam dwParam,
            ref Span <byte> buf,
            ref byte[] rented,
            int clearLen)
        {
            int len = buf.Length;

            if (!Interop.Advapi32.CryptGetProvParam(handle, dwParam, buf, ref len))
            {
                if (len > buf.Length)
                {
                    if (rented != null)
                    {
                        CryptoPool.Return(rented, clearLen);
                    }

                    rented = CryptoPool.Rent(len);
                    buf    = rented;
                    len    = rented.Length;
                }
                else
                {
                    throw Interop.CPError.GetLastWin32Error().ToCryptographicException();
                }

                if (!Interop.Advapi32.CryptGetProvParam(handle, dwParam, buf, ref len))
                {
                    throw Interop.CPError.GetLastWin32Error().ToCryptographicException();
                }
            }

            unsafe
            {
                fixed(byte *asciiPtr = &MemoryMarshal.GetReference(buf))
                {
                    return(Marshal.PtrToStringAnsi((IntPtr)asciiPtr, len));
                }
            }
        }
Beispiel #26
0
        public static ReadOnlyMemory <byte> Encrypt(
            ReadOnlyMemory <byte> plainText,
            ReadOnlyMemory <byte> key,
            ReadOnlyMemory <byte> iv
            )
        {
            if (!CalculateLength(plainText.Length, out int padSize, out int maxLength))
            {
                return(plainText);
            }

            using (var rental = CryptoPool.Rent <byte>(maxLength))
            {
                Memory <byte> plaintextRented;

                if (padSize == BlockSize)
                {
                    plaintextRented = rental.Memory.Slice(0, plainText.Length);
                    plainText.CopyTo(plaintextRented);
                }
                else
                {
                    plaintextRented = rental.Memory.Slice(0, maxLength);
                    plainText.CopyTo(plaintextRented);

                    plaintextRented.Span.Slice(plaintextRented.Length - padSize).Fill(0);
                }

                var aes = CryptoPal.Platform.Aes();

                var encrypted = aes.Encrypt(plaintextRented, key, iv);

                if (plainText.Length >= TwoBlockSizes)
                {
                    SwapLastTwoBlocks(encrypted.Span);
                }

                return(encrypted.Slice(0, plainText.Length));
            }
        }
Beispiel #27
0
            private static byte[]? DecryptContent(
                ReadOnlyMemory <byte> encryptedContent,
                byte[] cek,
                AlgorithmIdentifierAsn contentEncryptionAlgorithm,
                out Exception?exception)
            {
                exception = null;
                int encryptedContentLength = encryptedContent.Length;

                byte[]? encryptedContentArray = CryptoPool.Rent(encryptedContentLength);

                try
                {
                    encryptedContent.CopyTo(encryptedContentArray);

                    using (SymmetricAlgorithm alg = OpenAlgorithm(contentEncryptionAlgorithm))
                        using (ICryptoTransform decryptor = alg.CreateDecryptor(cek, alg.IV))
                        {
                            // If we extend this library to accept additional algorithm providers
                            // then a different array pool needs to be used.
                            Debug.Assert(alg.GetType().Assembly == typeof(Aes).Assembly);

                            return(decryptor.OneShot(
                                       encryptedContentArray,
                                       0,
                                       encryptedContentLength));
                        }
                }
                catch (CryptographicException e)
                {
                    exception = e;
                    return(null);
                }
                finally
                {
                    CryptoPool.Return(encryptedContentArray, encryptedContentLength);
                    encryptedContentArray = null;
                }
            }
Beispiel #28
0
        private static Memory <byte> PseudoRandomPlus(ReadOnlyMemory <byte> key, ReadOnlyMemory <byte> pepper, KerberosCryptoTransformer handler)
        {
            // PRF+(protocol key, octet string) -> (octet string)
            // PRF+(key, shared-info) := pseudo-random(key,  1 || shared-info ) ||
            //          pseudo-random(key, 2 || shared-info ) ||
            //          pseudo-random(key, 3 || shared-info ) || ...

            using (var pool = CryptoPool.Rent <byte>(pepper.Length + 1))
            {
                Memory <byte> input = pool.Memory.Slice(0, pepper.Length + 1);

                int prfSize = handler.BlockSize;

                int iterations = handler.KeySize / prfSize;

                if (handler.KeySize % prfSize > 0)
                {
                    iterations++;
                }

                input.Span[0] = 1;

                pepper.CopyTo(input.Slice(1));

                Memory <byte> result = new byte[prfSize * iterations];

                for (var i = 0; i < iterations; i++)
                {
                    handler.PseudoRandomFunction(key, input)
                    .Slice(0, prfSize)
                    .CopyTo(result.Slice(i * prfSize));

                    input.Span[0]++;
                }

                return(result);
            }
        }
Beispiel #29
0
        public override ReadOnlyMemory <byte> Encrypt(ReadOnlyMemory <byte> data, KerberosKey kerberosKey, KeyUsage usage)
        {
            var Ke = GetOrDeriveKey(kerberosKey, usage);

            var confounder = GenerateRandomBytes(ConfounderSize);

            var concatLength = confounder.Length + data.Length;

            using (var cleartextPool = CryptoPool.Rent <byte>(concatLength))
            {
                var cleartext = Concat(confounder.Span, data.Span, cleartextPool.Memory.Slice(0, concatLength));

                var encrypted = AESCTS.Encrypt(
                    cleartext,
                    Ke,
                    AllZerosInitVector
                    );

                var checksum = MakeChecksum(cleartext, kerberosKey, usage, KeyDerivationMode.Ki, ChecksumSize);

                return(Concat(encrypted.Span, checksum.Span));
            }
        }
Beispiel #30
0
        /// <summary>
        /// Purge the ticket cache of the provided Logon Id. Note that the value 0 zero is treated as the current users Logon Id.
        /// </summary>
        /// <param name="luid">The Logon Id of the cache to be purged.</param>
        public unsafe void PurgeTicketCache(long luid = 0)
        {
            var purgeRequest = new KERB_PURGE_TKT_CACHE_EX_REQUEST
            {
                MessageType = KERB_PROTOCOL_MESSAGE_TYPE.KerbPurgeTicketCacheExMessage,
                Flags       = 1,
                LogonId     = luid
            };

            var bufferSize = Marshal.SizeOf(typeof(KERB_PURGE_TKT_CACHE_EX_REQUEST));

            using (var pool = CryptoPool.Rent <byte>(bufferSize))
            {
                var buffer = pool.Memory.Slice(0, bufferSize);

                fixed(void *pBuffer = &MemoryMarshal.GetReference(buffer.Span))
                {
                    Marshal.StructureToPtr(purgeRequest, (IntPtr)pBuffer, false);

                    this.LsaCallAuthenticationPackage(pBuffer, bufferSize);
                }
            }
        }