pgpripemd160.c

来自「著名的加密软件的应用于电子邮件中」· C语言 代码 · 共 681 行 · 第 1/2 页

C
681
字号
{
	dword i;	/* counter */
	dword X[16];	/* message words */

memset(X, 0, 16*sizeof(dword));

/* put bytes from strptr into X */
for (i=0; i<(lswlen&63); i++) {
/* byte i goes into word X[i div 4] at pos. 8*(i mod 4) */
X[i>>2] ^= (dword) *strptr++ << (8 * (i&3));
}

	/* append the bit m_n == 1 */
	X[(lswlen>>2)&15] ^= (dword)1 << (8*(lswlen&3) + 7);

	if ((lswlen & 63) > 55) {
	/* length goes to next block */
	RMDcompress(MDbuf, X);
	memset(X, 0, 16*sizeof(dword));
	}

	/* append length in bits*/
	X[14] = lswlen << 3;
	X[15] = (lswlen >> 29) | (mswlen << 3);
	RMDcompress(MDbuf, X);

	return;
}

/************************ end of file rmd160.c **********************/
/* Remainder provides common interface used by PGP library */


/*
* Shuffle the bytes into little-endian order within words, as per the
* RIPEMD-160 spec (which follows MD4 conventions).
*/
static void
rmd160ByteSwap(word32 *dest, byte const *src, unsigned words)
	{
		do {
		 *dest++ = (word32)((unsigned)src[3] << 8 | src[2]) << 16 |
			((unsigned)src[1] << 8 | src[0]);
		 src += 4;
		} while (--words);
	}


/* Initialize the RIPEMD-160 values */

static void
rmd160Init(void *priv)
{
	struct RIPEMD160Context *ctx = (struct RIPEMD160Context *)priv;

	/* Set the h-vars to their initial values */
	RMDinit (ctx->iv);

	/* Initialise bit count */
	ctx->bytesHi = 0;
	ctx->bytesLo = 0;
}

/* Update the RIPEMD-160 hash state for a block of data. */

static void
rmd160Update(void *priv, byte const *buf, size_t len)
{
 struct RIPEMD160Context *ctx = (struct RIPEMD160Context *)priv;
 unsigned i;

 /* Update bitcount */

 word32 t = ctx->bytesLo;
 if ( ( ctx->bytesLo = t + len ) < t )
  ctx->bytesHi++; /* Carry from low to high */

 i = (unsigned)t % RIPEMD160_BLOCKBYTES; /* Bytes already in ctx->key */

 /* i is always less than RIPEMD160_BLOCKBYTES. */
 if (RIPEMD160_BLOCKBYTES-i > len) {
  memcpy((byte *)ctx->key + i, buf, len);
  return;
 }

 if (i) { /* First chunk is an odd size */
  memcpy((byte *)ctx->key + i, buf, RIPEMD160_BLOCKBYTES - i);
  rmd160ByteSwap(ctx->key, (byte *)ctx->key, RIPEMD160_BLOCKWORDS);
  RMDcompress(ctx->iv, ctx->key);
  buf += RIPEMD160_BLOCKBYTES-i;
  len -= RIPEMD160_BLOCKBYTES-i;
 }

 /* Process data in 64-byte chunks */
 while (len >= RIPEMD160_BLOCKBYTES) {
  rmd160ByteSwap(ctx->key, buf, RIPEMD160_BLOCKWORDS);
  RMDcompress(ctx->iv, ctx->key);
  buf += RIPEMD160_BLOCKBYTES;
  len -= RIPEMD160_BLOCKBYTES;
 }

 /* Handle any remaining bytes of data. */
 if (len)
  memcpy(ctx->key, buf, len);
}


/* Final wrapup - MD4 style padding on last block. */

static byte const *
rmd160Final(void *priv)
{
 struct RIPEMD160Context *ctx = (struct RIPEMD160Context *)priv;
 byte *digest;
 int i;
 word32 t;

 RMDfinish(ctx->iv, (byte *)ctx->key, ctx->bytesLo, ctx->bytesHi);

 digest = (byte *)ctx->iv;
 for (i = 0; i < RIPEMD160_HASHWORDS; i++) {
  t = ctx->iv[i];
  digest[0] = (byte)t;
  digest[1] = (byte)(t >> 8);
  digest[2] = (byte)(t >> 16);
  digest[3] = (byte)(t >> 24);
  digest += 4;
 }
 /* In case it's sensitive */
/* XXX memset(ctx, 0, sizeof(ctx)); */
 return (byte const *)ctx->iv;
}



/*
* RIPEM OID is 1.3.36.3.2.1, from URL above.
* The rest of the format is stolen from MD5. Do we need the @#$@$
* NULL in there?
*/
static byte const RIPEMD160DERprefix[] = {
 0x30, /* Universal, Constructed, Sequence */
 0x21, /* Length 33 (bytes following) */
  0x30, /* Universal, Constructed, Sequence */
  0x09, /* Length 9 */
   0x06, /* Universal, Primitive, object-identifier */
   0x05, /* Length 8 */
    43, /* 43 = ISO(1)*40 + 3 */
    36,
    3,
    2,
    1,
   0x05, /* Universal, Primitive, NULL */
   0x00, /* Length 0 */
  0x04, /* Universal, Primitive, Octet string */
  0x14 /* Length 20 */
   /* 20 RIPEMD-160 digest bytes go here */
};

struct PgpHash const HashRIPEMD160 = {
 "RIPEMD160", PGP_HASH_RIPEMD160,
 RIPEMD160DERprefix, sizeof(RIPEMD160DERprefix),
 RIPEMD160_HASHBYTES,
 sizeof(struct RIPEMD160Context),
 sizeof(struct{char _a; struct RIPEMD160Context _b;}) -
  sizeof(struct RIPEMD160Context),
 rmd160Init, rmd160Update, rmd160Final
};


#if TESTMAIN

/* --------------------------- RMD160 Test code --------------------------- */
#include <stdio.h>
#include <stdlib.h> /* For exit() */
#include <time.h>

/* Size of buffer for RMD160 speed test data */

#define TEST_BLOCK_SIZE	( RIPEMD160_HASHBYTES * 100 )

/* Number of bytes of test data to process */

#define TEST_BYTES 10000000L
#define TEST_BLOCKS	( TEST_BYTES / TEST_BLOCK_SIZE )

static char const *rmd160TestResults[] = {
		"9C1185A5C5E9FC54612808977EE8F548B2258D31",	/* "" */
		"0BDC9D2D256B3EE9DAAE347BE6F4DC835A467FFE",	/* "a" */
		"8EB208F7E05D987A9B044A8E98C6B087F15A0BFC",	/* "abc" */
		"5D0689EF49D2FAE572B881B123A85FFA21595F36",	/* "message digest" */
		"F71C27109C692C1B56BBDCEB5B9D2865B3708DBC",	/* "a..z" */
		"12A053384A9C0C88E405A06C27DCF49ADA62EB2B",	/* "abcdbcde...nopq" */
		"B0E20B6E3116640286ED3A87A5713079B21F5189",	/* "A..Za..z0..9" */
		"9B752E45573D4B39F4DBD3323CAB82BF63326BFB",	/* 8 * "1234567890" */
		"52783243C1697BDBE16D37F97F68F08325DC1528",	/* 1,000,000 "a" */
		"52783243C1697BDBE16D37F97F68F08325DC1528",	/* 1,000,000 "a" */
		"52783243C1697BDBE16D37F97F68F08325DC1528" };	/* 1,000,000 "a" */

static int
compareRMD160results(byte const *hash, int level)
{
 char buf[41];
 int i;

 for (i = 0; i < RIPEMD160_HASHBYTES; i++)
  sprintf(buf+2*i, "%02X", hash[i]);

 if (strcmp(buf, rmd160TestResults[level-1]) == 0) {
  printf("Test %d passed, result = %s\n", level, buf);
  return 0;
 } else {
  printf("Error in RMD160 implementation: Test %d failed\n", level);
  printf("  Result = %s\n", buf);
  printf("Expected = %s\n", rmd160TestResults[level-1]);
  return -1;
 }
}


int
main(void)
{
 struct RIPEMD160Context rmd160;
 byte data[TEST_BLOCK_SIZE];
 byte const *hash;
 clock_t ticks;
 long i;

 /*
 * Test output data, based on URL above.
 */
 rmd160Init(&rmd160);
 rmd160Update(&rmd160, (byte *)"", 0);
 hash = rmd160Final(&rmd160);
 if (compareRMD160results(hash, 1) < 0)
  exit (-1);

 rmd160Init(&rmd160);
 rmd160Update(&rmd160, (byte *)"a", 1);
 hash = rmd160Final(&rmd160);
 if (compareRMD160results(hash, 2) < 0)
  exit (-1);

 rmd160Init(&rmd160);
 rmd160Update(&rmd160, (byte *)"abc", 3);
 hash = rmd160Final(&rmd160);
 if (compareRMD160results(hash, 3) < 0)
  exit (-1);

 rmd160Init(&rmd160);
 rmd160Update(&rmd160, (byte *)"message digest", 14);
 hash = rmd160Final(&rmd160);
 if (compareRMD160results(hash, 4) < 0)
  exit (-1);

 rmd160Init(&rmd160);
 rmd160Update(&rmd160, (byte *)"abcdefghijklmnopqrstuvwxyz", 26);
 hash = rmd160Final(&rmd160);
 if (compareRMD160results(hash, 5) < 0)
  exit (-1);

 rmd160Init(&rmd160);
 rmd160Update(&rmd160, (byte *)"abcdbcdecdefdefgefghfghighijhijkijkl\
jklmklmnlmnomnopnopq", 56);
 hash = rmd160Final(&rmd160);
 if (compareRMD160results(hash, 6) < 0)
  exit (-1);

 rmd160Init(&rmd160);
 rmd160Update(&rmd160, (byte *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
abcdefghijklmnopqrstuvwxyz0123456789", 62);
 hash = rmd160Final(&rmd160);
 if (compareRMD160results(hash, 7) < 0)
  exit (-1);

 rmd160Init(&rmd160);
 rmd160Update(&rmd160, (byte *)"1234567890123456789012345678901234567890\
1234567890123456789012345678901234567890", 80);
 hash = rmd160Final(&rmd160);
 if (compareRMD160results(hash, 8) < 0)
  exit (-1);

 /* 1,000,000 bytes of ASCII 'a' (0x61), by 64's */
 rmd160Init(&rmd160);
 for (i = 0; i < 15625; i++)
  rmd160Update(&rmd160, (byte *)"aaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 64);
 hash = rmd160Final(&rmd160);
 if (compareRMD160results(hash, 9) < 0)
  exit (-1);

 /* 1,000,000 bytes of ASCII 'a' (0x61), by 25's */
 rmd160Init(&rmd160);
 for (i = 0; i < 40000; i++)
  rmd160Update(&rmd160, (byte *)"aaaaaaaaaaaaaaaaaaaaaaaaa", 25);
 hash = rmd160Final(&rmd160);
 if (compareRMD160results(hash, 10) < 0)
  exit (-1);

 /* 1,000,000 bytes of ASCII 'a' (0x61), by 125's */
 rmd160Init(&rmd160);
 for (i = 0; i < 8000; i++)
  rmd160Update(&rmd160, (byte *)"aaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 125);
 hash = rmd160Final(&rmd160);
 if (compareRMD160results(hash, 11) < 0)
  exit (-1);

 /* Now perform time trial, generating MD for 10MB of data. First,
 initialize the test data */
 memset(data, 0, TEST_BLOCK_SIZE);

 /* Get start time */
 printf("RMD160 time trial.  Processing %ld characters...\n", TEST_BYTES);
 ticks = clock();

 /* Calculate RMD160 message digest in TEST_BLOCK_SIZE byte blocks */
 rmd160Init(&rmd160);
 for (i = TEST_BLOCKS; i > 0; i--)
  rmd160Update(&rmd160, data, TEST_BLOCK_SIZE);
 hash = rmd160Final(&rmd160);

 /* Get finish time and print difference */
 ticks = clock() - ticks;
 printf("Ticks to process test input: %lu\n", (unsigned long)ticks);

 return 0;
}
#endif /* Test driver */

/*
* Local Variables:
* tab-width: 4
* End:
* vi: ts=4 sw=4
* vim: si
*/

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?