mirror of
https://github.com/transmission/transmission
synced 2024-12-27 18:18:10 +00:00
235 lines
6.5 KiB
C
235 lines
6.5 KiB
C
/*
|
|
sha1.c: Implementation of SHA-1 Secure Hash Algorithm-1
|
|
|
|
Based upon: NIST FIPS180-1 Secure Hash Algorithm-1
|
|
http://www.itl.nist.gov/fipspubs/fip180-1.htm
|
|
|
|
Non-official Japanese Translation by HIRATA Yasuyuki:
|
|
http://yasu.asuka.net/translations/SHA-1.html
|
|
|
|
Copyright (C) 2002 vi@nwr.jp. All rights reserved.
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
warranty. In no event will the authors be held liable for any damages
|
|
arising from the use of this software.
|
|
|
|
Permission is granted to anyone to use this software for any purpose,
|
|
including commercial applications, and to alter it and redistribute it
|
|
freely, subject to the following restrictions:
|
|
|
|
1. The origin of this software must not be misrepresented; you must not
|
|
claim that you wrote the original software. If you use this software
|
|
in a product, an acknowledgement in the product documentation would be
|
|
appreciated but is not required.
|
|
2. Altered source versions must be plainly marked as such, and must not be
|
|
misrepresented as beging the original software.
|
|
3. This notice may not be removed or altered from any source distribution.
|
|
|
|
Note:
|
|
The copyright notice above is copied from md5.h by L. Peter Deutsch
|
|
<ghost@aladdin.com>. Thank him since I'm not a good speaker of English. :)
|
|
*/
|
|
#include <string.h>
|
|
#include "sha1.h"
|
|
|
|
#define INLINE inline
|
|
/*
|
|
* Packing bytes to a word
|
|
*
|
|
* Should not assume p is aligned to word boundary
|
|
*/
|
|
static INLINE sha1_word_t packup(sha1_byte_t *p)
|
|
{
|
|
/* Portable, but slow */
|
|
return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3] << 0;
|
|
}
|
|
|
|
/*
|
|
* Unpacking a word to bytes
|
|
*
|
|
* Should not assume p is aligned to word boundary
|
|
*/
|
|
static void unpackup(sha1_byte_t *p, sha1_word_t q)
|
|
{
|
|
p[0] = (q >> 24) & 0xff;
|
|
p[1] = (q >> 16) & 0xff;
|
|
p[2] = (q >> 8) & 0xff;
|
|
p[3] = (q >> 0) & 0xff;
|
|
}
|
|
|
|
/*
|
|
* Processing a block
|
|
*/
|
|
static inline void sha1_update_now(sha1_state_s *pms, sha1_byte_t *bp)
|
|
{
|
|
sha1_word_t tmp, a, b, c, d, e, w[16+16];
|
|
int i, s;
|
|
|
|
/* pack 64 bytes into 16 words */
|
|
for(i = 0; i < 16; i++) {
|
|
w[i] = packup(bp + i * sizeof(sha1_word_t));
|
|
}
|
|
memcpy(w + 16, w + 0, sizeof(sha1_word_t) * 16);
|
|
|
|
a = pms->sha1_h[0], b = pms->sha1_h[1], c = pms->sha1_h[2], d = pms->sha1_h[3], e = pms->sha1_h[4];
|
|
|
|
#define rot(x,n) (((x) << n) | ((x) >> (32-n)))
|
|
#define f0(b, c, d) ((b&c)|(~b&d))
|
|
#define f1(b, c, d) (b^c^d)
|
|
#define f2(b, c, d) ((b&c)|(b&d)|(c&d))
|
|
#define f3(b, c, d) (b^c^d)
|
|
#define k0 0x5a827999
|
|
#define k1 0x6ed9eba1
|
|
#define k2 0x8f1bbcdc
|
|
#define k3 0xca62c1d6
|
|
|
|
/* t=0-15 */
|
|
s = 0;
|
|
for(i = 0; i < 16; i++) {
|
|
tmp = rot(a, 5) + f0(b, c, d) + e + w[s] + k0;
|
|
e = d; d = c; c = rot(b, 30); b = a; a = tmp;
|
|
s = (s + 1) % 16;
|
|
}
|
|
|
|
/* t=16-19 */
|
|
for(i = 16; i < 20; i++) {
|
|
w[s] = rot(w[s+13] ^ w[s+8] ^ w[s+2] ^ w[s], 1);
|
|
w[s+16] = w[s];
|
|
tmp = rot(a, 5) + f0(b, c, d) + e + w[s] + k0;
|
|
e = d; d = c; c = rot(b, 30); b = a; a = tmp;
|
|
s = (s + 1) % 16;
|
|
}
|
|
|
|
/* t=20-39 */
|
|
for(i = 0; i < 20; i++) {
|
|
w[s] = rot(w[s+13] ^ w[s+8] ^ w[s+2] ^ w[s], 1);
|
|
w[s+16] = w[s];
|
|
tmp = rot(a, 5) + f1(b, c, d) + e + w[s] + k1;
|
|
e = d; d = c; c = rot(b, 30); b = a; a = tmp;
|
|
s = (s + 1) % 16;
|
|
}
|
|
|
|
/* t=40-59 */
|
|
for(i = 0; i < 20; i++) {
|
|
w[s] = rot(w[s+13] ^ w[s+8] ^ w[s+2] ^ w[s], 1);
|
|
w[s+16] = w[s];
|
|
tmp = rot(a, 5) + f2(b, c, d) + e + w[s] + k2;
|
|
e = d; d = c; c = rot(b, 30); b = a; a = tmp;
|
|
s = (s + 1) % 16;
|
|
}
|
|
|
|
/* t=60-79 */
|
|
for(i = 0; i < 20; i++) {
|
|
w[s] = rot(w[s+13] ^ w[s+8] ^ w[s+2] ^ w[s], 1);
|
|
w[s+16] = w[s];
|
|
tmp = rot(a, 5) + f3(b, c, d) + e + w[s] + k3;
|
|
e = d; d = c; c = rot(b, 30); b = a; a = tmp;
|
|
s = (s + 1) % 16;
|
|
}
|
|
|
|
pms->sha1_h[0] += a, pms->sha1_h[1] += b, pms->sha1_h[2] += c, pms->sha1_h[3] += d, pms->sha1_h[4] += e;
|
|
}
|
|
|
|
/*
|
|
* Increment sha1_size1, sha1_size2 field of sha1_state_s
|
|
*/
|
|
static INLINE void incr(sha1_state_s *pms, int v)
|
|
{
|
|
sha1_word_t q;
|
|
|
|
q = pms->sha1_size1 + v * BITS;
|
|
if(q < pms->sha1_size1) {
|
|
pms->sha1_size2++;
|
|
}
|
|
pms->sha1_size1 = q;
|
|
}
|
|
|
|
/*
|
|
* Initialize sha1_state_s as FIPS specifies
|
|
*/
|
|
void sha1_init(sha1_state_s *pms)
|
|
{
|
|
memset(pms, 0, sizeof(*pms));
|
|
pms->sha1_h[0] = 0x67452301; /* Initialize H[0]-H[4] */
|
|
pms->sha1_h[1] = 0xEFCDAB89;
|
|
pms->sha1_h[2] = 0x98BADCFE;
|
|
pms->sha1_h[3] = 0x10325476;
|
|
pms->sha1_h[4] = 0xC3D2E1F0;
|
|
}
|
|
|
|
/*
|
|
* Fill block and update output when needed
|
|
*/
|
|
void sha1_update(sha1_state_s *pms, sha1_byte_t *bufp, int length)
|
|
{
|
|
/* Is the buffer partially filled? */
|
|
if(pms->sha1_count != 0) {
|
|
if(pms->sha1_count + length >= (signed) sizeof(pms->sha1_buf)) { /* buffer is filled enough */
|
|
int fil = sizeof(pms->sha1_buf) - pms->sha1_count; /* length to copy */
|
|
|
|
memcpy(pms->sha1_buf + pms->sha1_count, bufp, fil);
|
|
sha1_update_now(pms, pms->sha1_buf);
|
|
length -= fil;
|
|
bufp += fil;
|
|
pms->sha1_count = 0;
|
|
incr(pms, fil);
|
|
} else {
|
|
memcpy(pms->sha1_buf + pms->sha1_count, bufp, length);
|
|
pms->sha1_count += length;
|
|
incr(pms, length);
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* Loop to update state */
|
|
for(;;) {
|
|
if(length < (signed) sizeof(pms->sha1_buf)) { /* Short to fill up the buffer */
|
|
if(length) {
|
|
memcpy(pms->sha1_buf, bufp, length);
|
|
}
|
|
pms->sha1_count = length;
|
|
incr(pms, length);
|
|
break;
|
|
}
|
|
sha1_update_now(pms, bufp);
|
|
length -= sizeof(pms->sha1_buf);
|
|
bufp += sizeof(pms->sha1_buf);
|
|
incr(pms, sizeof(pms->sha1_buf));
|
|
}
|
|
}
|
|
|
|
void sha1_finish(sha1_state_s *pms, sha1_byte_t output[SHA1_OUTPUT_SIZE])
|
|
{
|
|
int i;
|
|
sha1_byte_t buf[1];
|
|
|
|
/* fill a bit */
|
|
buf[0] = 0x80;
|
|
sha1_update(pms, buf, 1);
|
|
|
|
/* Decrement sha1_size1, sha1_size2 */
|
|
if((pms->sha1_size1 -= BITS) == 0) {
|
|
pms->sha1_size2--;
|
|
}
|
|
|
|
/* fill zeros */
|
|
if(pms->sha1_count > (signed) (sizeof(pms->sha1_buf) - 2 * sizeof(sha1_word_t))) {
|
|
memset(pms->sha1_buf + pms->sha1_count, 0, sizeof(pms->sha1_buf) - pms->sha1_count);
|
|
sha1_update_now(pms, pms->sha1_buf);
|
|
pms->sha1_count = 0;
|
|
}
|
|
memset(pms->sha1_buf + pms->sha1_count, 0,
|
|
sizeof(pms->sha1_buf) - pms->sha1_count - sizeof(sha1_word_t) * 2);
|
|
|
|
/* fill last length */
|
|
unpackup(pms->sha1_buf + sizeof(pms->sha1_buf) - sizeof(sha1_word_t) * 2, pms->sha1_size2);
|
|
unpackup(pms->sha1_buf + sizeof(pms->sha1_buf) - sizeof(sha1_word_t) * 1, pms->sha1_size1);
|
|
|
|
/* final update */
|
|
sha1_update_now(pms, pms->sha1_buf);
|
|
|
|
/* move hash value to output byte array */
|
|
for(i = 0; i < (signed) (sizeof(pms->sha1_h)/sizeof(sha1_word_t)); i++) {
|
|
unpackup(output + i * sizeof(sha1_word_t), pms->sha1_h[i]);
|
|
}
|
|
}
|