An initialization vector IV can have any number of bits between 1 and
2^64. So it should be filled to the lower 64-bit in the last step
when computing ghash.

Signed-off-by: openluopworld <wuhanluop@163.com>
diff --git a/ChangeLog.d/bugfix-for-gcm-long-iv-size.txt b/ChangeLog.d/bugfix-for-gcm-long-iv-size.txt
new file mode 100644
index 0000000..0e46ad3
--- /dev/null
+++ b/ChangeLog.d/bugfix-for-gcm-long-iv-size.txt
@@ -0,0 +1,3 @@
+Bugfix
+   * Fix a bug in mbedtls_gcm_starts() when bits of iv are longer than 2^32.
+   * Fix #4884.
diff --git a/library/gcm.c b/library/gcm.c
index 2afe502..441ed69 100644
--- a/library/gcm.c
+++ b/library/gcm.c
@@ -111,6 +111,20 @@
 }
 #endif
 
+#ifndef PUT_UINT64_BE
+#define PUT_UINT64_BE( n, b, i )                                 \
+{                                                                \
+    ( b )[( i )    ] = (unsigned char) ( ( (n) >> 56 ) & 0xff ); \
+    ( b )[( i ) + 1] = (unsigned char) ( ( (n) >> 48 ) & 0xff ); \
+    ( b )[( i ) + 2] = (unsigned char) ( ( (n) >> 40 ) & 0xff ); \
+    ( b )[( i ) + 3] = (unsigned char) ( ( (n) >> 32 ) & 0xff ); \
+    ( b )[( i ) + 4] = (unsigned char) ( ( (n) >> 24 ) & 0xff ); \
+    ( b )[( i ) + 5] = (unsigned char) ( ( (n) >> 16 ) & 0xff ); \
+    ( b )[( i ) + 6] = (unsigned char) ( ( (n) >> 8  ) & 0xff ); \
+    ( b )[( i ) + 7] = (unsigned char) ( ( (n)       ) & 0xff ); \
+}
+#endif
+
 /*
  * Initialize a context
  */
@@ -309,6 +323,7 @@
     size_t i;
     const unsigned char *p;
     size_t use_len, olen = 0;
+    uint64_t iv_bits;
 
     GCM_VALIDATE_RET( ctx != NULL );
     GCM_VALIDATE_RET( iv != NULL );
@@ -338,7 +353,8 @@
     else
     {
         memset( work_buf, 0x00, 16 );
-        PUT_UINT32_BE( iv_len * 8, work_buf, 12 );
+        iv_bits = (uint64_t)iv_len * 8;
+        PUT_UINT64_BE( iv_bits, work_buf, 8 );
 
         p = iv;
         while( iv_len > 0 )