12 #if defined(CRYPTOPP_DISABLE_VMAC_ASM) 13 # undef CRYPTOPP_X86_ASM_AVAILABLE 14 # undef CRYPTOPP_X32_ASM_AVAILABLE 15 # undef CRYPTOPP_X64_ASM_AVAILABLE 16 # undef CRYPTOPP_SSE2_ASM_AVAILABLE 19 #if CRYPTOPP_MSC_VERSION 20 # pragma warning(disable: 4731) 25 #if defined(_MSC_VER) && !CRYPTOPP_BOOL_SLOW_WORD64 29 #if defined(CRYPTOPP_WORD128_AVAILABLE) && !defined(CRYPTOPP_X64_ASM_AVAILABLE) 30 # define VMAC_BOOL_WORD128 1 32 # define VMAC_BOOL_WORD128 0 36 #define const // Turbo C++ 2006 workaround 38 static const word64 p64 = W64LIT(0xfffffffffffffeff);
39 static const word64 m62 = W64LIT(0x3fffffffffffffff);
40 static const word64 m63 = W64LIT(0x7fffffffffffffff);
41 static const word64 m64 = W64LIT(0xffffffffffffffff);
42 static const word64 mpoly = W64LIT(0x1fffffff1fffffff);
49 #define m126 ((word128(m62)<<64)|m64) 51 static const word128 m126 = (word128(m62)<<64)|m64;
58 if (digestLength != 8 && digestLength != 16)
60 m_is128 = digestLength == 16;
63 if (m_L1KeyLength <= 0 || m_L1KeyLength % 128 != 0)
64 throw InvalidArgument(
"VMAC: L1KeyLength must be a positive multiple of 128");
69 cipher.
SetKey(userKey, keylength, params);
70 const unsigned int blockSize = cipher.
BlockSize();
71 const unsigned int blockSizeInWords = blockSize /
sizeof(word64);
80 ConditionalByteReverse<word64>(
BIG_ENDIAN_ORDER, m_nhKey(), m_nhKey(), m_nhKeySize()*
sizeof(word64));
85 for (i = 0; i <= (size_t)m_is128; i++)
96 word64 *l3Key = m_l3Key();
99 for (i = 0; i <= (size_t)m_is128; i++)
106 }
while ((l3Key[i*2+0] >= p64) || (l3Key[i*2+1] >= p64));
110 const byte *nonce = GetIVAndThrowIfInvalid(params, nonceLength);
122 size_t length = ThrowIfInvalidIVLength(len);
124 byte *storedNonce = m_nonce();
128 memset(storedNonce, 0, s-length);
129 memcpy(storedNonce+s-length, nonce, length);
134 if (m_padCached && (storedNonce[s-1] | 1) == (nonce[length-1] | 1))
137 for (
size_t i=0; m_padCached && i<s-length; i++)
138 m_padCached = (storedNonce[i] == 0);
142 memset(storedNonce, 0, s-length);
143 memcpy(storedNonce+s-length, nonce, length-1);
144 storedNonce[s-1] = nonce[length-1] & 0xfe;
148 storedNonce[s-1] = nonce[length-1];
150 m_isFirstBlock =
true;
154 void VMAC_Base::HashEndianCorrectedBlock(
const word64 *data)
156 CRYPTOPP_UNUSED(data);
158 throw NotImplemented(
"VMAC: HashEndianCorrectedBlock is not implemented");
164 #if CRYPTOPP_SSE2_ASM_AVAILABLE || defined(CRYPTOPP_X64_MASM_AVAILABLE) 170 #if CRYPTOPP_SSE2_ASM_AVAILABLE && (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32) 171 #if CRYPTOPP_MSC_VERSION 172 # pragma warning(disable: 4731) // frame pointer register 'ebp' modified by inline assembly code 176 __attribute__ ((noinline))
178 VMAC_Base::VHASH_Update_SSE2(
const word64 *data,
size_t blocksRemainingInWord64,
int tagPart)
183 const word64 *nhK = m_nhKey();
184 word64 *polyS = (word64*)(
void*)m_polyState();
188 CRYPTOPP_UNUSED(data); CRYPTOPP_UNUSED(tagPart); CRYPTOPP_UNUSED(L1KeyLength);
189 CRYPTOPP_UNUSED(blocksRemainingInWord64);
199 #
if defined(__INTEL_COMPILER)
200 char isFirstBlock = m_isFirstBlock;
201 AS2( mov ebx, [L1KeyLength])
202 AS2( mov dl, [isFirstBlock])
205 AS2( mov ebx, [ecx+m_L1KeyLength])
206 AS2( mov dl, [ecx+m_isFirstBlock])
208 AS2( mov eax, tagPart)
216 AS2( mov ecx, blocksRemainingInWord64)
220 #if CRYPTOPP_BOOL_X32 232 AS2( lea ebp, [edi+8*ebp])
233 AS2( movq mm6, [esi])
234 AS2( paddq mm6, [edi])
235 AS2( movq mm5, [esi+8])
236 AS2( paddq mm5, [edi+8])
240 ASS( pshufw mm2, mm6, 1, 0, 3, 2)
241 AS2( pmuludq mm6, mm5)
242 ASS( pshufw mm3, mm5, 1, 0, 3, 2)
243 AS2( pmuludq mm5, mm2)
244 AS2( pmuludq mm2, mm3)
245 AS2( pmuludq mm3, mm4)
247 AS2( movd [esp], mm6)
249 #if CRYPTOPP_BOOL_X32 250 AS2( movd [esp+8], mm5)
252 AS2( movd [esp+4], mm5)
258 AS2( movq mm0, [esi])
259 AS2( paddq mm0, [edi])
260 AS2( movq mm1, [esi+8])
261 AS2( paddq mm1, [edi+8])
266 ASS( pshufw mm2, mm0, 1, 0, 3, 2)
267 AS2( pmuludq mm0, mm1)
268 #if CRYPTOPP_BOOL_X32 269 AS2( movd [esp+16], mm3)
271 AS2( movd [esp+8], mm3)
275 ASS( pshufw mm3, mm1, 1, 0, 3, 2)
276 AS2( pmuludq mm1, mm2)
277 AS2( pmuludq mm2, mm3)
278 AS2( pmuludq mm3, mm4)
279 AS2( movd mm4, [esp])
281 #if CRYPTOPP_BOOL_X32 282 AS2( movd mm4, [esp+8])
284 AS2( movd mm4, [esp+16])
286 AS2( movd mm4, [esp+4])
288 AS2( movd mm4, [esp+8])
291 AS2( movd [esp], mm0)
294 #if CRYPTOPP_BOOL_X32 295 AS2( movd [esp+8], mm1)
297 AS2( movd [esp+4], mm1)
305 #if CRYPTOPP_BOOL_X32 306 AS2( movd [esp+16], mm3)
308 AS2( movd [esp+8], mm3)
312 AS2( movd mm4, [esp])
314 #if CRYPTOPP_BOOL_X32 315 AS2( movd mm4, [esp+8])
317 AS2( movd mm4, [esp+16])
319 AS2( movd mm4, [esp+4])
321 AS2( movd mm4, [esp+8])
324 AS2( lea ebp, [8*ebx])
327 AS2( movd [esp], mm7)
330 #if CRYPTOPP_BOOL_X32 331 AS2( movd [esp+8], mm6)
333 AS2( movd [esp+4], mm6)
344 #define k0 [eax+2*8+2*4] 345 #define k1 [eax+2*8+3*4] 346 #define k2 [eax+2*8+0*4] 347 #define k3 [eax+2*8+1*4] 351 AS2( movd mm0, [esp])
356 #if CRYPTOPP_BOOL_X32 357 AS2( movd mm2, [esp+8])
359 AS2( movd mm2, [esp+4])
373 AS2( pmuludq mm0, k3)
375 AS2( pmuludq mm1, k2)
378 AS2( pmuludq mm2, mm6)
384 AS2( pmuludq mm3, mm7)
385 AS2( pmuludq mm4, mm7)
386 AS2( pmuludq mm5, mm6)
391 AS2( pmuludq mm1, k2)
396 AS2( pmuludq mm2, k3)
397 AS2( pmuludq mm3, mm7)
398 #if CRYPTOPP_BOOL_X32 399 AS2( movd [esp+16], mm0)
401 AS2( movd [esp+8], mm0)
404 AS2( pmuludq mm7, mm5)
405 AS2( pmuludq mm5, k3)
408 AS2( pmuludq mm1, k2)
413 AS2( pmuludq mm2, mm6)
414 AS2( pmuludq mm6, a0)
417 AS2( movd mm3, [esp])
420 AS2( pmuludq mm3, k3)
423 AS2( pmuludq mm1, k2)
425 #if CRYPTOPP_BOOL_X32 426 AS2( movd mm2, [esp+8])
428 AS2( movd mm2, [esp+4])
436 #if CRYPTOPP_BOOL_X32 437 AS2( movd mm7, [esp+16])
439 AS2( movd mm7, [esp+8])
464 #if CRYPTOPP_BOOL_X32 475 :
"m" (L1KeyLength),
"c" (blocksRemainingInWord64),
"S" (data),
"D" (nhK+tagPart*2),
"d" (m_isFirstBlock),
"a" (polyS+tagPart*4)
482 #if VMAC_BOOL_WORD128 483 #define DeclareNH(a) word128 a=0 484 #define MUL64(rh,rl,i1,i2) {word128 p = word128(i1)*(i2); rh = word64(p>>64); rl = word64(p);} 485 #define AccumulateNH(a, b, c) a += word128(b)*(c) 486 #define Multiply128(r, i1, i2) r = word128(word64(i1)) * word64(i2) 488 #if _MSC_VER >= 1400 && !defined(__INTEL_COMPILER) && !defined(_M_ARM) 489 #define MUL32(a, b) __emulu(word32(a), word32(b)) 491 #define MUL32(a, b) ((word64)((word32)(a)) * (word32)(b)) 493 #if defined(CRYPTOPP_X64_ASM_AVAILABLE) 494 #define DeclareNH(a) word64 a##0=0, a##1=0 495 #define MUL64(rh,rl,i1,i2) asm ("mulq %3" : "=a"(rl), "=d"(rh) : "a"(i1), "g"(i2) : "cc"); 496 #define AccumulateNH(a, b, c) asm ("mulq %3; addq %%rax, %0; adcq %%rdx, %1" : "+r"(a##0), "+r"(a##1) : "a"(b), "g"(c) : "%rdx", "cc"); 497 #define ADD128(rh,rl,ih,il) asm ("addq %3, %1; adcq %2, %0" : "+r"(rh),"+r"(rl) : "r"(ih),"r"(il) : "cc"); 498 #elif defined(_MSC_VER) && !CRYPTOPP_BOOL_SLOW_WORD64 499 #define DeclareNH(a) word64 a##0=0, a##1=0 500 #define MUL64(rh,rl,i1,i2) (rl) = _umul128(i1,i2,&(rh)); 501 #define AccumulateNH(a, b, c) {\ 503 pl = _umul128(b,c,&ph);\ 505 a##1 += ph + (a##0 < pl);} 507 #define VMAC_BOOL_32BIT 1 508 #define DeclareNH(a) word64 a##0=0, a##1=0, a##2=0 509 #define MUL64(rh,rl,i1,i2) \ 510 { word64 _i1 = (i1), _i2 = (i2); \ 511 word64 m1= MUL32(_i1,_i2>>32); \ 512 word64 m2= MUL32(_i1>>32,_i2); \ 513 rh = MUL32(_i1>>32,_i2>>32); \ 514 rl = MUL32(_i1,_i2); \ 515 ADD128(rh,rl,(m1 >> 32),(m1 << 32)); \ 516 ADD128(rh,rl,(m2 >> 32),(m2 << 32)); \ 518 #define AccumulateNH(a, b, c) {\ 519 word64 p = MUL32(b, c);\ 520 a##1 += word32((p)>>32);\ 522 p = MUL32((b)>>32, c);\ 523 a##2 += word32((p)>>32);\ 525 p = MUL32((b)>>32, (c)>>32);\ 527 p = MUL32(b, (c)>>32);\ 529 a##2 += word32(p>>32);} 532 #ifndef VMAC_BOOL_32BIT 533 #define VMAC_BOOL_32BIT 0 536 #define ADD128(rh,rl,ih,il) \ 537 { word64 _il = (il); \ 539 (rh) += (ih) + ((rl) < (_il)); \ 543 template <
bool T_128BitTag>
544 void VMAC_Base::VHASH_Update_Template(
const word64 *data,
size_t blocksRemainingInWord64)
549 #define INNER_LOOP_ITERATION(j) {\ 550 word64 d0 = ConditionalByteReverse(LITTLE_ENDIAN_ORDER, data[i+2*j+0]);\ 551 word64 d1 = ConditionalByteReverse(LITTLE_ENDIAN_ORDER, data[i+2*j+1]);\ 552 AccumulateNH(nhA, d0+nhK[i+2*j+0], d1+nhK[i+2*j+1]);\ 554 AccumulateNH(nhB, d0+nhK[i+2*j+2], d1+nhK[i+2*j+3]);\ 557 size_t L1KeyLengthInWord64 = m_L1KeyLength / 8;
558 size_t innerLoopEnd = L1KeyLengthInWord64;
559 const word64 *nhK = m_nhKey();
560 word64 *polyS = (word64*)(
void*)m_polyState();
561 bool isFirstBlock =
true;
565 #if VMAC_BOOL_WORD128 568 word64 ah1=0, al1=0, ah2=0, al2=0;
570 word64 kh1, kl1, kh2, kl2;
571 kh1=(polyS+0*4+2)[0]; kl1=(polyS+0*4+2)[1];
574 kh2=(polyS+1*4+2)[0]; kl2=(polyS+1*4+2)[1];
584 if (blocksRemainingInWord64 < L1KeyLengthInWord64)
586 if (blocksRemainingInWord64 % 8)
588 innerLoopEnd = blocksRemainingInWord64 % 8;
589 for (; i<innerLoopEnd; i+=2)
590 INNER_LOOP_ITERATION(0);
592 innerLoopEnd = blocksRemainingInWord64;
594 for (; i<innerLoopEnd; i+=8)
596 INNER_LOOP_ITERATION(0);
597 INNER_LOOP_ITERATION(1);
598 INNER_LOOP_ITERATION(2);
599 INNER_LOOP_ITERATION(3);
601 blocksRemainingInWord64 -= innerLoopEnd;
602 data += innerLoopEnd;
605 word32 nh0[2], nh1[2];
608 nh0[0] = word32(nhA0);
609 nhA1 += (nhA0 >> 32);
610 nh1[0] = word32(nhA1);
611 nh2[0] = (nhA2 + (nhA1 >> 32)) & m62;
615 nh0[1] = word32(nhB0);
616 nhB1 += (nhB0 >> 32);
617 nh1[1] = word32(nhB1);
618 nh2[1] = (nhB2 + (nhB1 >> 32)) & m62;
621 #define a0 (((word32 *)(polyS+i*4))[2+NativeByteOrder::ToEnum()]) 622 #define a1 (*(((word32 *)(polyS+i*4))+3-NativeByteOrder::ToEnum())) // workaround for GCC 3.2 623 #define a2 (((word32 *)(polyS+i*4))[0+NativeByteOrder::ToEnum()]) 624 #define a3 (*(((word32 *)(polyS+i*4))+1-NativeByteOrder::ToEnum())) 625 #define aHi ((polyS+i*4)[0]) 626 #define k0 (((word32 *)(polyS+i*4+2))[2+NativeByteOrder::ToEnum()]) 627 #define k1 (*(((word32 *)(polyS+i*4+2))+3-NativeByteOrder::ToEnum())) 628 #define k2 (((word32 *)(polyS+i*4+2))[0+NativeByteOrder::ToEnum()]) 629 #define k3 (*(((word32 *)(polyS+i*4+2))+1-NativeByteOrder::ToEnum())) 630 #define kHi ((polyS+i*4+2)[0]) 634 isFirstBlock =
false;
637 m_isFirstBlock =
false;
638 for (i=0; i<=(size_t)T_128BitTag; i++)
640 word64 t = (word64)nh0[i] + k0;
642 t = (t >> 32) + nh1[i] + k1;
644 aHi = (t >> 32) + nh2[i] + kHi;
649 for (i=0; i<=(size_t)T_128BitTag; i++)
665 t = (word64(word32(p) & 0x7fffffff) << 32) | t2;
669 p += MUL32(a1, 2*k3);
670 p += MUL32(a2, 2*k2);
671 p += MUL32(a3, 2*k1);
677 p += MUL32(a2, 2*k3);
678 p += MUL32(a3, 2*k2);
694 #else // #if VMAC_BOOL_32BIT 697 isFirstBlock =
false;
700 m_isFirstBlock =
false;
701 #if VMAC_BOOL_WORD128 702 #define first_poly_step(a, kh, kl, m) a = (m & m126) + ((word128(kh) << 64) | kl) 704 first_poly_step(a1, kh1, kl1, nhA);
706 first_poly_step(a2, kh2, kl2, nhB);
708 #define first_poly_step(ah, al, kh, kl, mh, ml) {\ 710 ADD128(mh, ml, kh, kl); \ 713 first_poly_step(ah1, al1, kh1, kl1, nhA1, nhA0);
715 first_poly_step(ah2, al2, kh2, kl2, nhB1, nhB0);
721 #if VMAC_BOOL_WORD128 722 a1 = (word128((polyS+0*4)[0]) << 64) | (polyS+0*4)[1];
724 ah1=(polyS+0*4)[0]; al1=(polyS+0*4)[1];
728 #if VMAC_BOOL_WORD128 729 a2 = (word128((polyS+1*4)[0]) << 64) | (polyS+1*4)[1];
731 ah2=(polyS+1*4)[0]; al2=(polyS+1*4)[1];
737 #if VMAC_BOOL_WORD128 738 #define poly_step(a, kh, kl, m) \ 739 { word128 t1, t2, t3, t4;\ 740 Multiply128(t2, a>>64, kl);\ 741 Multiply128(t3, a, kh);\ 742 Multiply128(t1, a, kl);\ 743 Multiply128(t4, a>>64, 2*kh);\ 747 a = (word128(word64(t2)&m63) << 64) | word64(t4);\ 752 poly_step(a1, kh1, kl1, nhA);
754 poly_step(a2, kh2, kl2, nhB);
756 #define poly_step(ah, al, kh, kl, mh, ml) \ 757 { word64 t1h, t1l, t2h, t2l, t3h, t3l, z=0; \ 759 MUL64(t2h,t2l,ah,kl); \ 760 MUL64(t3h,t3l,al,kh); \ 761 MUL64(t1h,t1l,ah,2*kh); \ 762 MUL64(ah,al,al,kl); \ 764 ADD128(t2h,t2l,t3h,t3l); \ 766 ADD128(ah,al,t1h,t1l); \ 769 ADD128(t2h,ah,z,t2l); \ 771 t2h += t2h + (ah >> 63); \ 775 ADD128(ah,al,mh,ml); \ 776 ADD128(ah,al,z,t2h); \ 779 poly_step(ah1, al1, kh1, kl1, nhA1, nhA0);
781 poly_step(ah2, al2, kh2, kl2, nhB1, nhB0);
783 #endif // #if VMAC_BOOL_32BIT 784 }
while (blocksRemainingInWord64);
786 #if VMAC_BOOL_WORD128 787 (polyS+0*4)[0]=word64(a1>>64); (polyS+0*4)[1]=word64(a1);
790 (polyS+1*4)[0]=word64(a2>>64); (polyS+1*4)[1]=word64(a2);
792 #elif !VMAC_BOOL_32BIT 793 (polyS+0*4)[0]=ah1; (polyS+0*4)[1]=al1;
796 (polyS+1*4)[0]=ah2; (polyS+1*4)[1]=al2;
801 inline void VMAC_Base::VHASH_Update(
const word64 *data,
size_t blocksRemainingInWord64)
803 #if CRYPTOPP_SSE2_ASM_AVAILABLE && (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32) 806 VHASH_Update_SSE2(data, blocksRemainingInWord64, 0);
808 VHASH_Update_SSE2(data, blocksRemainingInWord64, 1);
809 m_isFirstBlock =
false;
815 VHASH_Update_Template<true>(data, blocksRemainingInWord64);
817 VHASH_Update_Template<false>(data, blocksRemainingInWord64);
821 size_t VMAC_Base::HashMultipleBlocks(
const word64 *data,
size_t length)
823 size_t remaining =
ModPowerOf2(length, m_L1KeyLength);
824 VHASH_Update(data, (length-remaining)/8);
828 static word64 L3Hash(
const word64 *input,
const word64 *l3Key,
size_t len)
830 word64 rh, rl, t, z=0;
831 word64 p1 = input[0], p2 = input[1];
832 word64 k1 = l3Key[0], k2 = l3Key[1];
837 ADD128(p1, p2, len, t);
839 t = (p1 > m63) + ((p1 == m63) & (p2 == m64));
840 ADD128(p1, p2, z, t);
846 t += (word32)t > 0xfffffffeU;
852 p1 += (0 - (p1 < k1)) & 257;
854 p2 += (0 - (p2 < k2)) & 257;
857 MUL64(rh, rl, p1, p2);
859 ADD128(t, rl, z, rh);
861 ADD128(t, rl, z, rh);
864 rl += (0 - (rl < t)) & 257;
865 rl += (0 - (rl > p64-1)) & 257;
873 size_t len =
ModPowerOf2(GetBitCountLo()/8, m_L1KeyLength);
877 memset(m_data()+len, 0, (0-len)%16);
878 VHASH_Update(DataBuf(), ((len+15)/16)*2);
881 else if (m_isFirstBlock)
884 m_polyState()[0] = m_polyState()[2];
885 m_polyState()[1] = m_polyState()[3];
888 m_polyState()[4] = m_polyState()[6];
889 m_polyState()[5] = m_polyState()[7];
896 t[0] = L3Hash(m_polyState(), m_l3Key(), len) + GetWord<word64>(
true,
BIG_ENDIAN_ORDER, m_pad());
897 t[1] = L3Hash(m_polyState()+4, m_l3Key()+2, len) + GetWord<word64>(
true,
BIG_ENDIAN_ORDER, m_pad()+8);
900 PutWord(
false, BIG_ENDIAN_ORDER, mac, t[0]);
901 PutWord(
false, BIG_ENDIAN_ORDER, mac+8, t[1]);
907 memcpy(mac, t, size);
912 word64 t = L3Hash(m_polyState(), m_l3Key(), len);
915 PutWord(
false, BIG_ENDIAN_ORDER, mac, t);
919 memcpy(mac, &t, size);
int GetIntValueWithDefault(const char *name, int defaultValue) const
Get a named value with type int, with default.
Standard names for retrieving values by name when working with NameValuePairs.
const char * DigestSize()
int, in bytes
An invalid argument was detected.
virtual void SetKey(const byte *key, size_t length, const NameValuePairs ¶ms=g_nullNameValuePairs)
Sets or reset the key of this object.
T2 ModPowerOf2(const T1 &a, const T2 &b)
Reduces a value to a power of 2.
void CleanNew(size_type newSize)
Change size without preserving contents.
void PutWord(bool assumeAligned, ByteOrder order, byte *block, T value, const byte *xorBlock=NULL)
Access a block of memory.
Secure memory block with allocator and cleanup.
Library configuration file.
Interface for random number generators.
Interface for one direction (encryption or decryption) of a block cipher.
Classes and functions for secure memory allocations.
bool IsAlignedOn(const void *ptr, unsigned int alignment)
Determines whether ptr is aligned to a minimum value.
Classes for the VMAC message authentication code.
A method was called which was not implemented.
unsigned int IVSize() const
Returns length of the IV accepted by this object.
T ConditionalByteReverse(ByteOrder order, T value)
Reverses bytes in a value depending upon endianness.
void UncheckedSetKey(const byte *userKey, unsigned int keylength, const NameValuePairs ¶ms)
Sets the key for this object without performing parameter validation.
SecBlock using AllocatorWithCleanup<byte, true> typedef.
#define CRYPTOPP_ASSERT(exp)
Debugging and diagnostic assertion.
Functions for CPU features and intrinsics.
void TruncatedFinal(byte *mac, size_t size)
Computes the hash of the current message.
const char * IV()
ConstByteArrayParameter, also accepts const byte * for backwards compatibility.
void Restart()
Restart the hash.
bool HasSSE2()
Determines SSE2 availability.
bool VerifyBufsEqual(const byte *buf1, const byte *buf2, size_t count)
Performs a near constant-time comparison of two equally sized buffers.
const char * L1KeyLength()
int, in bytes
unsigned int OptimalDataAlignment() const
Provides input and output data alignment for optimal performance.
Crypto++ library namespace.
void Resynchronize(const byte *nonce, int length=-1)
Resynchronize with an IV.
virtual void GetNextIV(RandomNumberGenerator &rng, byte *iv)
Retrieves a secure IV for the next message.
void GetNextIV(RandomNumberGenerator &rng, byte *IV)
Retrieves a secure IV for the next message.
Interface for retrieving values given their names.
byte * BytePtr()
Provides a byte pointer to the first element in the memory block.