Skip to content

Commit 72aecba

Browse files
committed
init cbc
1 parent fe478d2 commit 72aecba

File tree

1 file changed

+109
-91
lines changed

1 file changed

+109
-91
lines changed

src/DataProtection/DataProtection/src/Cng/CbcAuthenticatedEncryptor.cs

Lines changed: 109 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -56,89 +56,19 @@ public CbcAuthenticatedEncryptor(Secret keyDerivationKey, BCryptAlgorithmHandle
5656
_contextHeader = CreateContextHeader();
5757
}
5858

59-
private byte[] CreateContextHeader()
59+
public int GetDecryptedSize(int cipherTextLength)
6060
{
61-
var retVal = new byte[checked(
62-
1 /* KDF alg */
63-
+ 1 /* chaining mode */
64-
+ sizeof(uint) /* sym alg key size */
65-
+ sizeof(uint) /* sym alg block size */
66-
+ sizeof(uint) /* hmac alg key size */
67-
+ sizeof(uint) /* hmac alg digest size */
68-
+ _symmetricAlgorithmBlockSizeInBytes /* ciphertext of encrypted empty string */
69-
+ _hmacAlgorithmDigestLengthInBytes /* digest of HMACed empty string */)];
70-
71-
fixed (byte* pbRetVal = retVal)
72-
{
73-
byte* ptr = pbRetVal;
74-
75-
// First is the two-byte header
76-
*(ptr++) = 0; // 0x00 = SP800-108 CTR KDF w/ HMACSHA512 PRF
77-
*(ptr++) = 0; // 0x00 = CBC encryption + HMAC authentication
78-
79-
// Next is information about the symmetric algorithm (key size followed by block size)
80-
BitHelpers.WriteTo(ref ptr, _symmetricAlgorithmSubkeyLengthInBytes);
81-
BitHelpers.WriteTo(ref ptr, _symmetricAlgorithmBlockSizeInBytes);
82-
83-
// Next is information about the HMAC algorithm (key size followed by digest size)
84-
BitHelpers.WriteTo(ref ptr, _hmacAlgorithmSubkeyLengthInBytes);
85-
BitHelpers.WriteTo(ref ptr, _hmacAlgorithmDigestLengthInBytes);
86-
87-
// See the design document for an explanation of the following code.
88-
var tempKeys = new byte[_symmetricAlgorithmSubkeyLengthInBytes + _hmacAlgorithmSubkeyLengthInBytes];
89-
fixed (byte* pbTempKeys = tempKeys)
90-
{
91-
byte dummy;
92-
93-
// Derive temporary keys for encryption + HMAC.
94-
using (var provider = SP800_108_CTR_HMACSHA512Util.CreateEmptyProvider())
95-
{
96-
provider.DeriveKey(
97-
pbLabel: &dummy,
98-
cbLabel: 0,
99-
pbContext: &dummy,
100-
cbContext: 0,
101-
pbDerivedKey: pbTempKeys,
102-
cbDerivedKey: (uint)tempKeys.Length);
103-
}
104-
105-
// At this point, tempKeys := { K_E || K_H }.
106-
byte* pbSymmetricEncryptionSubkey = pbTempKeys;
107-
byte* pbHmacSubkey = &pbTempKeys[_symmetricAlgorithmSubkeyLengthInBytes];
108-
109-
// Encrypt a zero-length input string with an all-zero IV and copy the ciphertext to the return buffer.
110-
using (var symmetricKeyHandle = _symmetricAlgorithmHandle.GenerateSymmetricKey(pbSymmetricEncryptionSubkey, _symmetricAlgorithmSubkeyLengthInBytes))
111-
{
112-
fixed (byte* pbIV = new byte[_symmetricAlgorithmBlockSizeInBytes] /* will be zero-initialized */)
113-
{
114-
DoCbcEncrypt(
115-
symmetricKeyHandle: symmetricKeyHandle,
116-
pbIV: pbIV,
117-
pbInput: &dummy,
118-
cbInput: 0,
119-
pbOutput: ptr,
120-
cbOutput: _symmetricAlgorithmBlockSizeInBytes);
121-
}
122-
}
123-
ptr += _symmetricAlgorithmBlockSizeInBytes;
124-
125-
// MAC a zero-length input string and copy the digest to the return buffer.
126-
using (var hashHandle = _hmacAlgorithmHandle.CreateHmac(pbHmacSubkey, _hmacAlgorithmSubkeyLengthInBytes))
127-
{
128-
hashHandle.HashData(
129-
pbInput: &dummy,
130-
cbInput: 0,
131-
pbHashDigest: ptr,
132-
cbHashDigest: _hmacAlgorithmDigestLengthInBytes);
133-
}
61+
throw new NotImplementedException();
62+
}
13463

135-
ptr += _hmacAlgorithmDigestLengthInBytes;
136-
CryptoUtil.Assert(ptr - pbRetVal == retVal.Length, "ptr - pbRetVal == retVal.Length");
137-
}
138-
}
64+
public bool TryDecrypt(ReadOnlySpan<byte> cipherText, ReadOnlySpan<byte> additionalAuthenticatedData, Span<byte> destination, out int bytesWritten)
65+
{
66+
throw new NotImplementedException();
67+
}
13968

140-
// retVal := { version || chainingMode || symAlgKeySize || symAlgBlockSize || hmacAlgKeySize || hmacAlgDigestSize || E("") || MAC("") }.
141-
return retVal;
69+
public byte[] Decrypt(ArraySegment<byte> ciphertext, ArraySegment<byte> additionalAuthenticatedData)
70+
{
71+
throw new NotImplementedException();
14272
}
14373

14474
protected override byte[] DecryptImpl(byte* pbCiphertext, uint cbCiphertext, byte* pbAdditionalAuthenticatedData, uint cbAdditionalAuthenticatedData)
@@ -202,14 +132,6 @@ protected override byte[] DecryptImpl(byte* pbCiphertext, uint cbCiphertext, byt
202132
}
203133
}
204134

205-
public override void Dispose()
206-
{
207-
_sp800_108_ctr_hmac_provider.Dispose();
208-
209-
// We don't want to dispose of the underlying algorithm instances because they
210-
// might be reused.
211-
}
212-
213135
// 'pbIV' must be a pointer to a buffer equal in length to the symmetric algorithm block size.
214136
private byte[] DoCbcDecrypt(BCryptKeyHandle symmetricKeyHandle, byte* pbIV, byte* pbInput, uint cbInput)
215137
{
@@ -299,13 +221,13 @@ private void DoCbcEncrypt(BCryptKeyHandle symmetricKeyHandle, byte* pbIV, byte*
299221
CryptoUtil.Assert(dwEncryptedBytes == cbOutput, "dwEncryptedBytes == cbOutput");
300222
}
301223

302-
public override int GetEncryptedSize(int plainTextLength)
224+
public int GetEncryptedSize(int plainTextLength)
303225
{
304226
uint paddedCiphertextLength = GetCbcEncryptedOutputSizeWithPadding((uint)plainTextLength);
305227
return checked((int)(KEY_MODIFIER_SIZE_IN_BYTES + _symmetricAlgorithmBlockSizeInBytes + paddedCiphertextLength + _hmacAlgorithmDigestLengthInBytes));
306228
}
307229

308-
public override bool TryEncrypt(ReadOnlySpan<byte> plaintext, ReadOnlySpan<byte> additionalAuthenticatedData, Span<byte> destination, out int bytesWritten)
230+
public bool TryEncrypt(ReadOnlySpan<byte> plaintext, ReadOnlySpan<byte> additionalAuthenticatedData, Span<byte> destination, out int bytesWritten)
309231
{
310232
bytesWritten = 0;
311233

@@ -404,7 +326,10 @@ public override bool TryEncrypt(ReadOnlySpan<byte> plaintext, ReadOnlySpan<byte>
404326
}
405327
}
406328

407-
public override byte[] Encrypt(ArraySegment<byte> plaintext, ArraySegment<byte> additionalAuthenticatedData, uint preBufferSize, uint postBufferSize)
329+
public byte[] Encrypt(ArraySegment<byte> plaintext, ArraySegment<byte> additionalAuthenticatedData)
330+
=> Encrypt(plaintext, additionalAuthenticatedData, 0, 0);
331+
332+
public byte[] Encrypt(ArraySegment<byte> plaintext, ArraySegment<byte> additionalAuthenticatedData, uint preBufferSize, uint postBufferSize)
408333
{
409334
plaintext.Validate();
410335
additionalAuthenticatedData.Validate();
@@ -490,4 +415,97 @@ private bool ValidateHash(BCryptHashHandle hashHandle, byte* pbInput, uint cbInp
490415
hashHandle.HashData(pbInput, cbInput, pbActualDigest, _hmacAlgorithmDigestLengthInBytes);
491416
return CryptoUtil.TimeConstantBuffersAreEqual(pbExpectedDigest, pbActualDigest, _hmacAlgorithmDigestLengthInBytes);
492417
}
418+
419+
private byte[] CreateContextHeader()
420+
{
421+
var retVal = new byte[checked(
422+
1 /* KDF alg */
423+
+ 1 /* chaining mode */
424+
+ sizeof(uint) /* sym alg key size */
425+
+ sizeof(uint) /* sym alg block size */
426+
+ sizeof(uint) /* hmac alg key size */
427+
+ sizeof(uint) /* hmac alg digest size */
428+
+ _symmetricAlgorithmBlockSizeInBytes /* ciphertext of encrypted empty string */
429+
+ _hmacAlgorithmDigestLengthInBytes /* digest of HMACed empty string */)];
430+
431+
fixed (byte* pbRetVal = retVal)
432+
{
433+
byte* ptr = pbRetVal;
434+
435+
// First is the two-byte header
436+
*(ptr++) = 0; // 0x00 = SP800-108 CTR KDF w/ HMACSHA512 PRF
437+
*(ptr++) = 0; // 0x00 = CBC encryption + HMAC authentication
438+
439+
// Next is information about the symmetric algorithm (key size followed by block size)
440+
BitHelpers.WriteTo(ref ptr, _symmetricAlgorithmSubkeyLengthInBytes);
441+
BitHelpers.WriteTo(ref ptr, _symmetricAlgorithmBlockSizeInBytes);
442+
443+
// Next is information about the HMAC algorithm (key size followed by digest size)
444+
BitHelpers.WriteTo(ref ptr, _hmacAlgorithmSubkeyLengthInBytes);
445+
BitHelpers.WriteTo(ref ptr, _hmacAlgorithmDigestLengthInBytes);
446+
447+
// See the design document for an explanation of the following code.
448+
var tempKeys = new byte[_symmetricAlgorithmSubkeyLengthInBytes + _hmacAlgorithmSubkeyLengthInBytes];
449+
fixed (byte* pbTempKeys = tempKeys)
450+
{
451+
byte dummy;
452+
453+
// Derive temporary keys for encryption + HMAC.
454+
using (var provider = SP800_108_CTR_HMACSHA512Util.CreateEmptyProvider())
455+
{
456+
provider.DeriveKey(
457+
pbLabel: &dummy,
458+
cbLabel: 0,
459+
pbContext: &dummy,
460+
cbContext: 0,
461+
pbDerivedKey: pbTempKeys,
462+
cbDerivedKey: (uint)tempKeys.Length);
463+
}
464+
465+
// At this point, tempKeys := { K_E || K_H }.
466+
byte* pbSymmetricEncryptionSubkey = pbTempKeys;
467+
byte* pbHmacSubkey = &pbTempKeys[_symmetricAlgorithmSubkeyLengthInBytes];
468+
469+
// Encrypt a zero-length input string with an all-zero IV and copy the ciphertext to the return buffer.
470+
using (var symmetricKeyHandle = _symmetricAlgorithmHandle.GenerateSymmetricKey(pbSymmetricEncryptionSubkey, _symmetricAlgorithmSubkeyLengthInBytes))
471+
{
472+
fixed (byte* pbIV = new byte[_symmetricAlgorithmBlockSizeInBytes] /* will be zero-initialized */)
473+
{
474+
DoCbcEncrypt(
475+
symmetricKeyHandle: symmetricKeyHandle,
476+
pbIV: pbIV,
477+
pbInput: &dummy,
478+
cbInput: 0,
479+
pbOutput: ptr,
480+
cbOutput: _symmetricAlgorithmBlockSizeInBytes);
481+
}
482+
}
483+
ptr += _symmetricAlgorithmBlockSizeInBytes;
484+
485+
// MAC a zero-length input string and copy the digest to the return buffer.
486+
using (var hashHandle = _hmacAlgorithmHandle.CreateHmac(pbHmacSubkey, _hmacAlgorithmSubkeyLengthInBytes))
487+
{
488+
hashHandle.HashData(
489+
pbInput: &dummy,
490+
cbInput: 0,
491+
pbHashDigest: ptr,
492+
cbHashDigest: _hmacAlgorithmDigestLengthInBytes);
493+
}
494+
495+
ptr += _hmacAlgorithmDigestLengthInBytes;
496+
CryptoUtil.Assert(ptr - pbRetVal == retVal.Length, "ptr - pbRetVal == retVal.Length");
497+
}
498+
}
499+
500+
// retVal := { version || chainingMode || symAlgKeySize || symAlgBlockSize || hmacAlgKeySize || hmacAlgDigestSize || E("") || MAC("") }.
501+
return retVal;
502+
}
503+
504+
public void Dispose()
505+
{
506+
_sp800_108_ctr_hmac_provider.Dispose();
507+
508+
// We don't want to dispose of the underlying algorithm instances because they
509+
// might be reused.
510+
}
493511
}

0 commit comments

Comments
 (0)