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; }
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)); }
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(); }
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; }
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); } }