public override void GenerateKey()
        {
            var key = new byte[8];

            RandomNumberGenerator.Fill(key);
            // Never hand back a weak or semi-weak key
            while (IsWeakKey(key) || IsSemiWeakKey(key))
            {
                RandomNumberGenerator.Fill(key);
            }
            KeyValue = key;
        }
Esempio n. 2
0
        private static void FillRandomAsciiString(Span <char> destination)
        {
            Debug.Assert(destination.Length < 128);
            Span <byte> randomKey = stackalloc byte[destination.Length];

            RandomNumberGenerator.Fill(randomKey);

            for (int i = 0; i < randomKey.Length; i++)
            {
                // 33 (!) up to 33 + 63 = 96 (`)
                destination[i] = (char)(33 + (randomKey[i] & 0b0011_1111));
            }
        }
        private ICryptoTransform CreateTransform(byte[] rgbKey, byte[]?rgbIV, bool encrypting)
        {
            // note: rgbIV is guaranteed to be cloned before this method, so no need to clone it again

            if (rgbKey == null)
            {
                throw new ArgumentNullException(nameof(rgbKey));
            }

            long keySize = rgbKey.Length * (long)BitsPerByte;

            if (keySize > int.MaxValue || !((int)keySize).IsLegalSize(LegalKeySizes))
            {
                throw new ArgumentException(SR.Cryptography_InvalidKeySize, nameof(rgbKey));
            }

            if (IsWeakKey(rgbKey))
            {
                throw new CryptographicException(SR.Cryptography_InvalidKey_Weak, "DES");
            }
            if (IsSemiWeakKey(rgbKey))
            {
                throw new CryptographicException(SR.Cryptography_InvalidKey_SemiWeak, "DES");
            }

            if (rgbIV == null)
            {
                if (Mode.UsesIv())
                {
                    rgbIV = new byte[8];
                    RandomNumberGenerator.Fill(rgbIV);
                }
            }
            else
            {
                // We truncate IV's that are longer than the block size to 8 bytes : this is
                // done to maintain backward .NET Framework compatibility with the behavior shipped in V1.x.
                // The call to set the IV in CryptoAPI will ignore any bytes after the first 8
                // bytes. We'll still reject IV's that are shorter than the block size though.
                if (rgbIV.Length < 8)
                {
                    throw new CryptographicException(SR.Cryptography_InvalidIVSize);
                }
            }

            BasicSymmetricCipher cipher = new BasicSymmetricCipherCsp(CapiHelper.CALG_DES, Mode, BlockSize / BitsPerByte, rgbKey, 0, false, rgbIV, encrypting, FeedbackSize, this.GetPaddingSize());

            return(UniversalCryptoTransform.Create(Padding, cipher, encrypting));
        }
Esempio n. 4
0
        public Rfc2898DeriveBytes(string password, int saltSize, int iterations, HashAlgorithmName hashAlgorithm)
        {
            if (saltSize < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(saltSize), SR.ArgumentOutOfRange_NeedNonNegNum);
            }
            if (iterations <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(iterations), SR.ArgumentOutOfRange_NeedPosNum);
            }

            _salt = new byte[saltSize + sizeof(uint)];
            RandomNumberGenerator.Fill(_salt.AsSpan(0, saltSize));

            _iterations = (uint)iterations;
            byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
            HashAlgorithm = hashAlgorithm;
            _hmac         = OpenHmac(passwordBytes);
            CryptographicOperations.ZeroMemory(passwordBytes);
            // _blockSize is in bytes, HashSize is in bits.
            _blockSize = _hmac.HashSize >> 3;

            Initialize();
        }
Esempio n. 5
0
        internal static unsafe bool ExportPkcs8KeyBlob(
            bool allocate,
            SafeNCryptKeyHandle keyHandle,
            ReadOnlySpan <char> password,
            int kdfCount,
            Span <byte> destination,
            out int bytesWritten,
            out byte[]?allocated)
        {
            using (SafeUnicodeStringHandle stringHandle = new SafeUnicodeStringHandle(password))
            {
                fixed(byte *oidPtr = s_pkcs12TripleDesOidBytes)
                {
                    Interop.NCrypt.NCryptBuffer *buffers = stackalloc Interop.NCrypt.NCryptBuffer[3];

                    Interop.NCrypt.PBE_PARAMS pbeParams = default;
                    Span <byte> salt = new Span <byte>(pbeParams.rgbSalt, Interop.NCrypt.PBE_PARAMS.RgbSaltSize);

                    RandomNumberGenerator.Fill(salt);
                    pbeParams.Params.cbSalt      = salt.Length;
                    pbeParams.Params.iIterations = kdfCount;

                    buffers[0] = new Interop.NCrypt.NCryptBuffer
                    {
                        BufferType = Interop.NCrypt.BufferType.PkcsSecret,
                        cbBuffer   = checked (2 * (password.Length + 1)),
                        pvBuffer   = stringHandle.DangerousGetHandle(),
                    };

                    if (buffers[0].pvBuffer == IntPtr.Zero)
                    {
                        buffers[0].cbBuffer = 0;
                    }

                    buffers[1] = new Interop.NCrypt.NCryptBuffer
                    {
                        BufferType = Interop.NCrypt.BufferType.PkcsAlgOid,
                        cbBuffer   = s_pkcs12TripleDesOidBytes.Length,
                        pvBuffer   = (IntPtr)oidPtr,
                    };

                    buffers[2] = new Interop.NCrypt.NCryptBuffer
                    {
                        BufferType = Interop.NCrypt.BufferType.PkcsAlgParam,
                        cbBuffer   = sizeof(Interop.NCrypt.PBE_PARAMS),
                        pvBuffer   = (IntPtr)(&pbeParams),
                    };

                    Interop.NCrypt.NCryptBufferDesc desc = new Interop.NCrypt.NCryptBufferDesc
                    {
                        cBuffers  = 3,
                        pBuffers  = (IntPtr)buffers,
                        ulVersion = 0,
                    };

                    Span <byte> empty = default;

                    ErrorCode errorCode = Interop.NCrypt.NCryptExportKey(
                        keyHandle,
                        IntPtr.Zero,
                        Interop.NCrypt.NCRYPT_PKCS8_PRIVATE_KEY_BLOB,
                        ref desc,
                        ref MemoryMarshal.GetReference(empty),
                        0,
                        out int numBytesNeeded,
                        0);

                    if (errorCode != ErrorCode.ERROR_SUCCESS)
                    {
                        throw errorCode.ToCryptographicException();
                    }

                    allocated = null;

                    if (allocate)
                    {
                        allocated   = new byte[numBytesNeeded];
                        destination = allocated;
                    }
                    else if (numBytesNeeded > destination.Length)
                    {
                        bytesWritten = 0;
                        return(false);
                    }

                    errorCode = Interop.NCrypt.NCryptExportKey(
                        keyHandle,
                        IntPtr.Zero,
                        Interop.NCrypt.NCRYPT_PKCS8_PRIVATE_KEY_BLOB,
                        ref desc,
                        ref MemoryMarshal.GetReference(destination),
                        destination.Length,
                        out numBytesNeeded,
                        0);

                    if (errorCode != ErrorCode.ERROR_SUCCESS)
                    {
                        throw errorCode.ToCryptographicException();
                    }

                    if (allocate && numBytesNeeded != destination.Length)
                    {
                        byte[] trimmed = new byte[numBytesNeeded];
                        destination.Slice(0, numBytesNeeded).CopyTo(trimmed);
                        CryptographicOperations.ZeroMemory(allocated.AsSpan(0, numBytesNeeded));
                        allocated = trimmed;
                    }

                    bytesWritten = numBytesNeeded;
                    return(true);
                }
            }
        }
        internal void PadOaep(
            ReadOnlySpan <byte> source,
            Span <byte> destination)
        {
            // https://tools.ietf.org/html/rfc3447#section-7.1.1

            byte[]? dbMask = null;
            Span <byte> dbMaskSpan = Span <byte> .Empty;

            try
            {
                // Since the biggest known _hLen is 512/8 (64) and destination.Length is 0 or more,
                // this shouldn't underflow without something having severely gone wrong.
                int maxInput = checked (destination.Length - _hLen - _hLen - 2);

                // 1(a) does not apply, we do not allow custom label values.

                // 1(b)
                if (source.Length > maxInput)
                {
                    throw new CryptographicException(
                              SR.Format(SR.Cryptography_Encryption_MessageTooLong, maxInput));
                }

                // The final message (step 2(i)) will be
                // 0x00 || maskedSeed (hLen long) || maskedDB (rest of the buffer)
                Span <byte> seed = destination.Slice(1, _hLen);
                Span <byte> db   = destination.Slice(1 + _hLen);

                using (IncrementalHash hasher = IncrementalHash.CreateHash(_hashAlgorithmName))
                {
                    // DB = lHash || PS || 0x01 || M
                    Span <byte> lHash = db.Slice(0, _hLen);
                    Span <byte> mDest = db.Slice(db.Length - source.Length);
                    Span <byte> ps    = db.Slice(_hLen, db.Length - _hLen - 1 - mDest.Length);
                    Span <byte> psEnd = db.Slice(_hLen + ps.Length, 1);

                    // 2(a) lHash = Hash(L), where L is the empty string.
                    if (!hasher.TryGetHashAndReset(lHash, out int hLen2) || hLen2 != _hLen)
                    {
                        Debug.Fail("TryGetHashAndReset failed with exact-size destination");
                        throw new CryptographicException();
                    }

                    // 2(b) generate a padding string of all zeros equal to the amount of unused space.
                    ps.Clear();

                    // 2(c)
                    psEnd[0] = 0x01;

                    // still 2(c)
                    source.CopyTo(mDest);

                    // 2(d)
                    RandomNumberGenerator.Fill(seed);

                    // 2(e)
                    dbMask     = CryptoPool.Rent(db.Length);
                    dbMaskSpan = new Span <byte>(dbMask, 0, db.Length);
                    Mgf1(hasher, seed, dbMaskSpan);

                    // 2(f)
                    Xor(db, dbMaskSpan);

                    // 2(g)
                    Span <byte> seedMask = stackalloc byte[_hLen];
                    Mgf1(hasher, db, seedMask);

                    // 2(h)
                    Xor(seed, seedMask);

                    // 2(i)
                    destination[0] = 0;
                }
            }
            catch (Exception e) when(!(e is CryptographicException))
            {
                Debug.Fail("Bad exception produced from OAEP padding: " + e);
                throw new CryptographicException();
            }
            finally
            {
                if (dbMask != null)
                {
                    CryptographicOperations.ZeroMemory(dbMaskSpan);
                    CryptoPool.Return(dbMask, clearSize: 0);
                }
            }
        }
        internal void EncodePss(ReadOnlySpan <byte> mHash, Span <byte> destination, int keySize)
        {
            // https://tools.ietf.org/html/rfc3447#section-9.1.1
            int emBits = keySize - 1;
            int emLen  = BytesRequiredForBitCount(emBits);

            if (mHash.Length != _hLen)
            {
                throw new CryptographicException(SR.Cryptography_SignHash_WrongSize);
            }

            // In this implementation, sLen is restricted to the length of the input hash.
            int sLen = _hLen;

            // 3.  if emLen < hLen + sLen + 2, encoding error.
            //
            // sLen = hLen in this implementation.

            if (emLen < 2 + _hLen + sLen)
            {
                throw new CryptographicException(SR.Cryptography_KeyTooSmall);
            }

            // Set any leading bytes to zero, since that will be required for the pending
            // RSA operation.
            destination.Slice(0, destination.Length - emLen).Clear();

            // 12. Let EM = maskedDB || H || 0xbc (H has length hLen)
            Span <byte> em = destination.Slice(destination.Length - emLen, emLen);

            int dbLen = emLen - _hLen - 1;

            Span <byte> db    = em.Slice(0, dbLen);
            Span <byte> hDest = em.Slice(dbLen, _hLen);

            em[emLen - 1] = 0xBC;

            byte[]      dbMaskRented = CryptoPool.Rent(dbLen);
            Span <byte> dbMask       = new Span <byte>(dbMaskRented, 0, dbLen);

            using (IncrementalHash hasher = IncrementalHash.CreateHash(_hashAlgorithmName))
            {
                // 4. Generate a random salt of length sLen
                Span <byte> salt = stackalloc byte[sLen];
                RandomNumberGenerator.Fill(salt);

                // 5. Let M' = an octet string of 8 zeros concat mHash concat salt
                // 6. Let H = Hash(M')

                hasher.AppendData(EightZeros);
                hasher.AppendData(mHash);
                hasher.AppendData(salt);

                if (!hasher.TryGetHashAndReset(hDest, out int hLen2) || hLen2 != _hLen)
                {
                    Debug.Fail("TryGetHashAndReset failed with exact-size destination");
                    throw new CryptographicException();
                }

                // 7. Generate PS as zero-valued bytes of length emLen - sLen - hLen - 2.
                // 8. Let DB = PS || 0x01 || salt
                int psLen = emLen - sLen - _hLen - 2;
                db.Slice(0, psLen).Clear();
                db[psLen] = 0x01;
                salt.CopyTo(db.Slice(psLen + 1));

                // 9. Let dbMask = MGF(H, emLen - hLen - 1)
                Mgf1(hasher, hDest, dbMask);

                // 10. Let maskedDB = DB XOR dbMask
                Xor(db, dbMask);

                // 11. Set the "unused" bits in the leftmost byte of maskedDB to 0.
                int unusedBits = 8 * emLen - emBits;

                if (unusedBits != 0)
                {
                    byte mask = (byte)(0xFF >> unusedBits);
                    db[0] &= mask;
                }
            }

            CryptographicOperations.ZeroMemory(dbMask);
            CryptoPool.Return(dbMaskRented, clearSize: 0);
        }
 public override void GenerateKey()
 {
     var key = new byte[KeySizeValue / 8];
     RandomNumberGenerator.Fill(key);
     KeyValue = key;
 }
Esempio n. 9
0
        public static int PadBlock(ReadOnlySpan <byte> block, Span <byte> destination, int paddingSizeInBytes, PaddingMode paddingMode)
        {
            int count            = block.Length;
            int paddingRemainder = count % paddingSizeInBytes;
            int padBytes         = paddingSizeInBytes - paddingRemainder;

            switch (paddingMode)
            {
            case PaddingMode.None when(paddingRemainder != 0):
                throw new CryptographicException(SR.Cryptography_PartialBlock);

            case PaddingMode.None:
                if (destination.Length < count)
                {
                    throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination));
                }

                block.CopyTo(destination);
                return(count);

            // ANSI padding fills the blocks with zeros and adds the total number of padding bytes as
            // the last pad byte, adding an extra block if the last block is complete.
            //
            // xx 00 00 00 00 00 00 07
            case PaddingMode.ANSIX923:
                int ansiSize = count + padBytes;

                if (destination.Length < ansiSize)
                {
                    throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination));
                }

                block.CopyTo(destination);
                destination.Slice(count, padBytes - 1).Clear();
                destination[count + padBytes - 1] = (byte)padBytes;
                return(ansiSize);

            // ISO padding fills the blocks up with random bytes and adds the total number of padding
            // bytes as the last pad byte, adding an extra block if the last block is complete.
            //
            // xx rr rr rr rr rr rr 07
            case PaddingMode.ISO10126:
                int isoSize = count + padBytes;

                if (destination.Length < isoSize)
                {
                    throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination));
                }

                block.CopyTo(destination);
                RandomNumberGenerator.Fill(destination.Slice(count, padBytes - 1));
                destination[count + padBytes - 1] = (byte)padBytes;
                return(isoSize);

            // PKCS padding fills the blocks up with bytes containing the total number of padding bytes
            // used, adding an extra block if the last block is complete.
            //
            // xx xx 06 06 06 06 06 06
            case PaddingMode.PKCS7:
                int pkcsSize = count + padBytes;

                if (destination.Length < pkcsSize)
                {
                    throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination));
                }

                block.CopyTo(destination);
                destination.Slice(count, padBytes).Fill((byte)padBytes);
                return(pkcsSize);

            // Zeros padding fills the last partial block with zeros, and does not add a new block to
            // the end if the last block is already complete.
            //
            //  xx 00 00 00 00 00 00 00
            case PaddingMode.Zeros:
                if (padBytes == paddingSizeInBytes)
                {
                    padBytes = 0;
                }

                int zeroSize = count + padBytes;

                if (destination.Length < zeroSize)
                {
                    throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination));
                }

                block.CopyTo(destination);
                destination.Slice(count, padBytes).Clear();
                return(zeroSize);

            default:
                throw new CryptographicException(SR.Cryptography_UnknownPaddingMode);
            }
        }