12 #if defined(_MSC_VER) && !CRYPTOPP_BOOL_SLOW_WORD64 16 #if defined(CRYPTOPP_DISABLE_VMAC_ASM) 17 # undef CRYPTOPP_X86_ASM_AVAILABLE 18 # undef CRYPTOPP_X32_ASM_AVAILABLE 19 # undef CRYPTOPP_X64_ASM_AVAILABLE 20 # undef CRYPTOPP_SSE2_ASM_AVAILABLE 23 #if CRYPTOPP_MSC_VERSION 24 # pragma warning(disable: 4731) 27 ANONYMOUS_NAMESPACE_BEGIN
29 #if defined(CRYPTOPP_WORD128_AVAILABLE) && !defined(CRYPTOPP_X64_ASM_AVAILABLE) 30 using CryptoPP::word128;
31 using CryptoPP::word64;
32 # define VMAC_BOOL_WORD128 1 34 using CryptoPP::word64;
35 # define VMAC_BOOL_WORD128 0 39 #define const // Turbo C++ 2006 workaround 41 const word64 p64 = W64LIT(0xfffffffffffffeff);
42 const word64 m62 = W64LIT(0x3fffffffffffffff);
43 const word64 m63 = W64LIT(0x7fffffffffffffff);
44 const word64 m64 = W64LIT(0xffffffffffffffff);
45 const word64 mpoly = W64LIT(0x1fffffff1fffffff);
52 #define m126 ((word128(m62)<<64)|m64) 54 const word128 m126 = (word128(m62)<<64)|m64;
58 ANONYMOUS_NAMESPACE_END
64 int digestLength = params.GetIntValueWithDefault(
Name::DigestSize(), DefaultDigestSize());
65 if (digestLength != 8 && digestLength != 16)
67 m_is128 = digestLength == 16;
70 if (m_L1KeyLength <= 0 || m_L1KeyLength % 128 != 0)
71 throw InvalidArgument(
"VMAC: L1KeyLength must be a positive multiple of 128");
76 cipher.
SetKey(userKey, keylength, params);
77 const unsigned int blockSize = cipher.
BlockSize();
78 const unsigned int blockSizeInWords = blockSize /
sizeof(word64);
87 ConditionalByteReverse<word64>(
BIG_ENDIAN_ORDER, m_nhKey(), m_nhKey(), m_nhKeySize()*
sizeof(word64));
92 for (i = 0; i <= (size_t)m_is128; i++)
103 word64 *l3Key = m_l3Key();
106 for (i = 0; i <= (size_t)m_is128; i++)
113 }
while ((l3Key[i*2+0] >= p64) || (l3Key[i*2+1] >= p64));
117 const byte *nonce = GetIVAndThrowIfInvalid(params, nonceLength);
118 Resynchronize(nonce, (
int)nonceLength);
129 size_t length = ThrowIfInvalidIVLength(len);
131 byte *storedNonce = m_nonce();
135 memset(storedNonce, 0, s-length);
136 memcpy(storedNonce+s-length, nonce, length);
141 if (m_padCached && (storedNonce[s-1] | 1) == (nonce[length-1] | 1))
144 for (
size_t i=0; m_padCached && i<s-length; i++)
145 m_padCached = (storedNonce[i] == 0);
149 memset(storedNonce, 0, s-length);
150 memcpy(storedNonce+s-length, nonce, length-1);
151 storedNonce[s-1] = nonce[length-1] & 0xfe;
155 storedNonce[s-1] = nonce[length-1];
157 m_isFirstBlock =
true;
161 void VMAC_Base::HashEndianCorrectedBlock(
const word64 *data)
163 CRYPTOPP_UNUSED(data);
165 throw NotImplemented(
"VMAC: HashEndianCorrectedBlock is not implemented");
171 #if CRYPTOPP_SSE2_ASM_AVAILABLE || defined(CRYPTOPP_X64_MASM_AVAILABLE) 177 #if CRYPTOPP_SSE2_ASM_AVAILABLE && CRYPTOPP_BOOL_X86 178 #if CRYPTOPP_MSC_VERSION 179 # pragma warning(disable: 4731) // frame pointer register 'ebp' modified by inline assembly code 183 __attribute__ ((noinline))
185 VMAC_Base::VHASH_Update_SSE2(
const word64 *data,
size_t blocksRemainingInWord64,
int tagPart)
190 const word64 *nhK = m_nhKey();
191 word64 *polyS = (word64*)(
void*)m_polyState();
195 CRYPTOPP_UNUSED(data); CRYPTOPP_UNUSED(tagPart); CRYPTOPP_UNUSED(
L1KeyLength);
196 CRYPTOPP_UNUSED(blocksRemainingInWord64);
206 #
if defined(__INTEL_COMPILER)
207 char isFirstBlock = m_isFirstBlock;
209 AS2( mov dl, [isFirstBlock])
212 AS2( mov ebx, [ecx+m_L1KeyLength])
213 AS2( mov dl, [ecx+m_isFirstBlock])
215 AS2( mov eax, tagPart)
223 AS2( mov ecx, blocksRemainingInWord64)
234 AS2( lea ebp, [edi+8*ebp])
235 AS2( movq mm6, [esi])
236 AS2( paddq mm6, [edi])
237 AS2( movq mm5, [esi+8])
238 AS2( paddq mm5, [edi+8])
242 ASS( pshufw mm2, mm6, 1, 0, 3, 2)
243 AS2( pmuludq mm6, mm5)
244 ASS( pshufw mm3, mm5, 1, 0, 3, 2)
245 AS2( pmuludq mm5, mm2)
246 AS2( pmuludq mm2, mm3)
247 AS2( pmuludq mm3, mm4)
249 AS2( movd [esp], mm6)
251 AS2( movd [esp+4], mm5)
256 AS2( movq mm0, [esi])
257 AS2( paddq mm0, [edi])
258 AS2( movq mm1, [esi+8])
259 AS2( paddq mm1, [edi+8])
264 ASS( pshufw mm2, mm0, 1, 0, 3, 2)
265 AS2( pmuludq mm0, mm1)
266 AS2( movd [esp+8], mm3)
269 ASS( pshufw mm3, mm1, 1, 0, 3, 2)
270 AS2( pmuludq mm1, mm2)
271 AS2( pmuludq mm2, mm3)
272 AS2( pmuludq mm3, mm4)
273 AS2( movd mm4, [esp])
275 AS2( movd mm4, [esp+4])
277 AS2( movd mm4, [esp+8])
279 AS2( movd [esp], mm0)
282 AS2( movd [esp+4], mm1)
289 AS2( movd [esp+8], mm3)
292 AS2( movd mm4, [esp])
294 AS2( movd mm4, [esp+4])
296 AS2( movd mm4, [esp+8])
298 AS2( lea ebp, [8*ebx])
301 AS2( movd [esp], mm7)
304 AS2( movd [esp+4], mm6)
314 #define k0 [eax+2*8+2*4] 315 #define k1 [eax+2*8+3*4] 316 #define k2 [eax+2*8+0*4] 317 #define k3 [eax+2*8+1*4] 321 AS2( movd mm0, [esp])
326 AS2( movd mm2, [esp+4])
339 AS2( pmuludq mm0, k3)
341 AS2( pmuludq mm1, k2)
344 AS2( pmuludq mm2, mm6)
350 AS2( pmuludq mm3, mm7)
351 AS2( pmuludq mm4, mm7)
352 AS2( pmuludq mm5, mm6)
357 AS2( pmuludq mm1, k2)
362 AS2( pmuludq mm2, k3)
363 AS2( pmuludq mm3, mm7)
364 AS2( movd [esp+8], mm0)
366 AS2( pmuludq mm7, mm5)
367 AS2( pmuludq mm5, k3)
370 AS2( pmuludq mm1, k2)
375 AS2( pmuludq mm2, mm6)
376 AS2( pmuludq mm6, a0)
379 AS2( movd mm3, [esp])
382 AS2( pmuludq mm3, k3)
385 AS2( pmuludq mm1, k2)
387 AS2( movd mm2, [esp+4])
394 AS2( movd mm7, [esp+8])
425 :
"m" (
L1KeyLength),
"c" (blocksRemainingInWord64),
"S" (data),
"D" (nhK+tagPart*2),
"d" (m_isFirstBlock),
"a" (polyS+tagPart*4)
432 #if VMAC_BOOL_WORD128 433 #define DeclareNH(a) word128 a=0 434 #define MUL64(rh,rl,i1,i2) {word128 p = word128(i1)*(i2); rh = word64(p>>64); rl = word64(p);} 435 #define AccumulateNH(a, b, c) a += word128(b)*(c) 436 #define Multiply128(r, i1, i2) r = word128(word64(i1)) * word64(i2) 438 #if _MSC_VER >= 1400 && !defined(__INTEL_COMPILER) && (defined(_M_IX86) || defined(_M_X64) || defined(_M_IA64)) 439 #define MUL32(a, b) __emulu(word32(a), word32(b)) 441 #define MUL32(a, b) ((word64)((word32)(a)) * (word32)(b)) 443 #if defined(CRYPTOPP_X64_ASM_AVAILABLE) 444 #define DeclareNH(a) word64 a##0=0, a##1=0 445 #define MUL64(rh,rl,i1,i2) asm ("mulq %3" : "=a"(rl), "=d"(rh) : "a"(i1), "g"(i2) : "cc"); 446 #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"); 447 #define ADD128(rh,rl,ih,il) asm ("addq %3, %1; adcq %2, %0" : "+r"(rh),"+r"(rl) : "r"(ih),"r"(il) : "cc"); 448 #elif defined(_MSC_VER) && !CRYPTOPP_BOOL_SLOW_WORD64 449 #define DeclareNH(a) word64 a##0=0, a##1=0 450 #define MUL64(rh,rl,i1,i2) (rl) = _umul128(i1,i2,&(rh)); 451 #define AccumulateNH(a, b, c) {\ 453 pl = _umul128(b,c,&ph);\ 455 a##1 += ph + (a##0 < pl);} 457 #define VMAC_BOOL_32BIT 1 458 #define DeclareNH(a) word64 a##0=0, a##1=0, a##2=0 459 #define MUL64(rh,rl,i1,i2) \ 460 { word64 _i1 = (i1), _i2 = (i2); \ 461 word64 m1= MUL32(_i1,_i2>>32); \ 462 word64 m2= MUL32(_i1>>32,_i2); \ 463 rh = MUL32(_i1>>32,_i2>>32); \ 464 rl = MUL32(_i1,_i2); \ 465 ADD128(rh,rl,(m1 >> 32),(m1 << 32)); \ 466 ADD128(rh,rl,(m2 >> 32),(m2 << 32)); \ 468 #define AccumulateNH(a, b, c) {\ 469 word64 p = MUL32(b, c);\ 470 a##1 += word32((p)>>32);\ 472 p = MUL32((b)>>32, c);\ 473 a##2 += word32((p)>>32);\ 475 p = MUL32((b)>>32, (c)>>32);\ 477 p = MUL32(b, (c)>>32);\ 479 a##2 += word32(p>>32);} 482 #ifndef VMAC_BOOL_32BIT 483 #define VMAC_BOOL_32BIT 0 486 #define ADD128(rh,rl,ih,il) \ 487 { word64 _il = (il); \ 489 (rh) += (ih) + ((rl) < (_il)); \ 493 template <
bool T_128BitTag>
494 void VMAC_Base::VHASH_Update_Template(
const word64 *data,
size_t blocksRemainingInWord64)
499 #define INNER_LOOP_ITERATION(j) {\ 500 word64 d0 = ConditionalByteReverse(LITTLE_ENDIAN_ORDER, data[i+2*j+0]);\ 501 word64 d1 = ConditionalByteReverse(LITTLE_ENDIAN_ORDER, data[i+2*j+1]);\ 502 AccumulateNH(nhA, d0+nhK[i+2*j+0], d1+nhK[i+2*j+1]);\ 504 AccumulateNH(nhB, d0+nhK[i+2*j+2], d1+nhK[i+2*j+3]);\ 507 size_t L1KeyLengthInWord64 = m_L1KeyLength / 8;
508 size_t innerLoopEnd = L1KeyLengthInWord64;
509 const word64 *nhK = m_nhKey();
510 word64 *polyS = (word64*)(
void*)m_polyState();
511 bool isFirstBlock =
true;
515 #if VMAC_BOOL_WORD128 518 word64 ah1=0, al1=0, ah2=0, al2=0;
520 word64 kh1, kl1, kh2, kl2;
521 kh1=(polyS+0*4+2)[0]; kl1=(polyS+0*4+2)[1];
524 kh2=(polyS+1*4+2)[0]; kl2=(polyS+1*4+2)[1];
534 if (blocksRemainingInWord64 < L1KeyLengthInWord64)
536 if (blocksRemainingInWord64 % 8)
538 innerLoopEnd = blocksRemainingInWord64 % 8;
539 for (; i<innerLoopEnd; i+=2)
540 INNER_LOOP_ITERATION(0);
542 innerLoopEnd = blocksRemainingInWord64;
544 for (; i<innerLoopEnd; i+=8)
546 INNER_LOOP_ITERATION(0);
547 INNER_LOOP_ITERATION(1);
548 INNER_LOOP_ITERATION(2);
549 INNER_LOOP_ITERATION(3);
551 blocksRemainingInWord64 -= innerLoopEnd;
552 data += innerLoopEnd;
555 word32 nh0[2], nh1[2];
558 nh0[0] = word32(nhA0);
559 nhA1 += (nhA0 >> 32);
560 nh1[0] = word32(nhA1);
561 nh2[0] = (nhA2 + (nhA1 >> 32)) & m62;
565 nh0[1] = word32(nhB0);
566 nhB1 += (nhB0 >> 32);
567 nh1[1] = word32(nhB1);
568 nh2[1] = (nhB2 + (nhB1 >> 32)) & m62;
571 #define a0 (((word32 *)(polyS+i*4))[2+NativeByteOrder::ToEnum()]) 572 #define a1 (*(((word32 *)(polyS+i*4))+3-NativeByteOrder::ToEnum())) // workaround for GCC 3.2 573 #define a2 (((word32 *)(polyS+i*4))[0+NativeByteOrder::ToEnum()]) 574 #define a3 (*(((word32 *)(polyS+i*4))+1-NativeByteOrder::ToEnum())) 575 #define aHi ((polyS+i*4)[0]) 576 #define k0 (((word32 *)(polyS+i*4+2))[2+NativeByteOrder::ToEnum()]) 577 #define k1 (*(((word32 *)(polyS+i*4+2))+3-NativeByteOrder::ToEnum())) 578 #define k2 (((word32 *)(polyS+i*4+2))[0+NativeByteOrder::ToEnum()]) 579 #define k3 (*(((word32 *)(polyS+i*4+2))+1-NativeByteOrder::ToEnum())) 580 #define kHi ((polyS+i*4+2)[0]) 584 isFirstBlock =
false;
587 m_isFirstBlock =
false;
588 for (i=0; i<=(size_t)T_128BitTag; i++)
590 word64 t = (word64)nh0[i] + k0;
592 t = (t >> 32) + nh1[i] + k1;
594 aHi = (t >> 32) + nh2[i] + kHi;
599 for (i=0; i<=(size_t)T_128BitTag; i++)
615 t = (word64(word32(p) & 0x7fffffff) << 32) | t2;
619 p += MUL32(a1, 2*k3);
620 p += MUL32(a2, 2*k2);
621 p += MUL32(a3, 2*k1);
627 p += MUL32(a2, 2*k3);
628 p += MUL32(a3, 2*k2);
644 #else // #if VMAC_BOOL_32BIT 647 isFirstBlock =
false;
650 m_isFirstBlock =
false;
651 #if VMAC_BOOL_WORD128 652 #define first_poly_step(a, kh, kl, m) a = (m & m126) + ((word128(kh) << 64) | kl) 654 first_poly_step(a1, kh1, kl1, nhA);
656 first_poly_step(a2, kh2, kl2, nhB);
658 #define first_poly_step(ah, al, kh, kl, mh, ml) {\ 660 ADD128(mh, ml, kh, kl); \ 663 first_poly_step(ah1, al1, kh1, kl1, nhA1, nhA0);
665 first_poly_step(ah2, al2, kh2, kl2, nhB1, nhB0);
671 #if VMAC_BOOL_WORD128 672 a1 = (word128((polyS+0*4)[0]) << 64) | (polyS+0*4)[1];
674 ah1=(polyS+0*4)[0]; al1=(polyS+0*4)[1];
678 #if VMAC_BOOL_WORD128 679 a2 = (word128((polyS+1*4)[0]) << 64) | (polyS+1*4)[1];
681 ah2=(polyS+1*4)[0]; al2=(polyS+1*4)[1];
687 #if VMAC_BOOL_WORD128 688 #define poly_step(a, kh, kl, m) \ 689 { word128 t1, t2, t3, t4;\ 690 Multiply128(t2, a>>64, kl);\ 691 Multiply128(t3, a, kh);\ 692 Multiply128(t1, a, kl);\ 693 Multiply128(t4, a>>64, 2*kh);\ 697 a = (word128(word64(t2)&m63) << 64) | word64(t4);\ 702 poly_step(a1, kh1, kl1, nhA);
704 poly_step(a2, kh2, kl2, nhB);
706 #define poly_step(ah, al, kh, kl, mh, ml) \ 707 { word64 t1h, t1l, t2h, t2l, t3h, t3l, z=0; \ 709 MUL64(t2h,t2l,ah,kl); \ 710 MUL64(t3h,t3l,al,kh); \ 711 MUL64(t1h,t1l,ah,2*kh); \ 712 MUL64(ah,al,al,kl); \ 714 ADD128(t2h,t2l,t3h,t3l); \ 716 ADD128(ah,al,t1h,t1l); \ 719 ADD128(t2h,ah,z,t2l); \ 721 t2h += t2h + (ah >> 63); \ 725 ADD128(ah,al,mh,ml); \ 726 ADD128(ah,al,z,t2h); \ 729 poly_step(ah1, al1, kh1, kl1, nhA1, nhA0);
731 poly_step(ah2, al2, kh2, kl2, nhB1, nhB0);
733 #endif // #if VMAC_BOOL_32BIT 734 }
while (blocksRemainingInWord64);
736 #if VMAC_BOOL_WORD128 737 (polyS+0*4)[0]=word64(a1>>64); (polyS+0*4)[1]=word64(a1);
740 (polyS+1*4)[0]=word64(a2>>64); (polyS+1*4)[1]=word64(a2);
742 #elif !VMAC_BOOL_32BIT 743 (polyS+0*4)[0]=ah1; (polyS+0*4)[1]=al1;
746 (polyS+1*4)[0]=ah2; (polyS+1*4)[1]=al2;
751 inline void VMAC_Base::VHASH_Update(
const word64 *data,
size_t blocksRemainingInWord64)
753 #if CRYPTOPP_SSE2_ASM_AVAILABLE && CRYPTOPP_BOOL_X86 756 VHASH_Update_SSE2(data, blocksRemainingInWord64, 0);
758 VHASH_Update_SSE2(data, blocksRemainingInWord64, 1);
759 m_isFirstBlock =
false;
765 VHASH_Update_Template<true>(data, blocksRemainingInWord64);
767 VHASH_Update_Template<false>(data, blocksRemainingInWord64);
771 size_t VMAC_Base::HashMultipleBlocks(
const word64 *data,
size_t length)
773 size_t remaining =
ModPowerOf2(length, m_L1KeyLength);
774 VHASH_Update(data, (length-remaining)/8);
778 word64 L3Hash(
const word64 *input,
const word64 *l3Key,
size_t len)
780 word64 rh, rl, t, z=0;
781 word64 p1 = input[0], p2 = input[1];
782 word64 k1 = l3Key[0], k2 = l3Key[1];
787 ADD128(p1, p2, len, t);
789 t = (p1 > m63) + ((p1 == m63) & (p2 == m64));
790 ADD128(p1, p2, z, t);
796 t += (word32)t > 0xfffffffeU;
802 p1 += (0 - (p1 < k1)) & 257;
804 p2 += (0 - (p2 < k2)) & 257;
807 MUL64(rh, rl, p1, p2);
809 ADD128(t, rl, z, rh);
811 ADD128(t, rl, z, rh);
814 rl += (0 - (rl < t)) & 257;
815 rl += (0 - (rl > p64-1)) & 257;
823 size_t len =
ModPowerOf2(GetBitCountLo()/8, m_L1KeyLength);
827 memset(m_data()+len, 0, (0-len)%16);
828 VHASH_Update(DataBuf(), ((len+15)/16)*2);
831 else if (m_isFirstBlock)
834 m_polyState()[0] = m_polyState()[2];
835 m_polyState()[1] = m_polyState()[3];
838 m_polyState()[4] = m_polyState()[6];
839 m_polyState()[5] = m_polyState()[7];
846 t[0] = L3Hash(m_polyState(), m_l3Key(), len) + GetWord<word64>(
true,
BIG_ENDIAN_ORDER, m_pad());
847 t[1] = L3Hash(m_polyState()+4, m_l3Key()+2, len) + GetWord<word64>(
true,
BIG_ENDIAN_ORDER, m_pad()+8);
857 memcpy(mac, t, size);
862 word64 t = L3Hash(m_polyState(), m_l3Key(), len);
869 memcpy(mac, &t, size);
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.
VMAC message authentication code base class.
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.
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.