1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 /* SPDX-License-Identifier: Unlicense */
3 #include "tomcrypt_private.h"
4 
5 /**
6    @file adler32.c
7    Adler-32 checksum algorithm
8    Written and placed in the public domain by Wei Dai
9    Adapted for libtomcrypt by Steffen Jaeckel
10 */
11 #ifdef LTC_ADLER32
12 
13 static const unsigned long s_adler32_base = 65521;
14 
adler32_init(adler32_state * ctx)15 void adler32_init(adler32_state *ctx)
16 {
17    LTC_ARGCHKVD(ctx != NULL);
18    ctx->s[0] = 1;
19    ctx->s[1] = 0;
20 }
21 
adler32_update(adler32_state * ctx,const unsigned char * input,unsigned long length)22 void adler32_update(adler32_state *ctx, const unsigned char *input, unsigned long length)
23 {
24    unsigned long s1, s2;
25 
26    LTC_ARGCHKVD(ctx != NULL);
27    LTC_ARGCHKVD(input != NULL);
28    s1 = ctx->s[0];
29    s2 = ctx->s[1];
30 
31    if (length % 8 != 0) {
32       do {
33          s1 += *input++;
34          s2 += s1;
35          length--;
36       } while (length % 8 != 0);
37 
38       if (s1 >= s_adler32_base) {
39          s1 -= s_adler32_base;
40       }
41       s2 %= s_adler32_base;
42    }
43 
44    while (length > 0) {
45       s1 += input[0];
46       s2 += s1;
47       s1 += input[1];
48       s2 += s1;
49       s1 += input[2];
50       s2 += s1;
51       s1 += input[3];
52       s2 += s1;
53       s1 += input[4];
54       s2 += s1;
55       s1 += input[5];
56       s2 += s1;
57       s1 += input[6];
58       s2 += s1;
59       s1 += input[7];
60       s2 += s1;
61 
62       length -= 8;
63       input += 8;
64 
65       if (s1 >= s_adler32_base) {
66          s1 -= s_adler32_base;
67       }
68       s2 %= s_adler32_base;
69    }
70 
71    LTC_ARGCHKVD(s1 < s_adler32_base);
72    LTC_ARGCHKVD(s2 < s_adler32_base);
73 
74    ctx->s[0] = (unsigned short)s1;
75    ctx->s[1] = (unsigned short)s2;
76 }
77 
adler32_finish(const adler32_state * ctx,void * hash,unsigned long size)78 void adler32_finish(const adler32_state *ctx, void *hash, unsigned long size)
79 {
80    unsigned char* h;
81 
82    LTC_ARGCHKVD(ctx != NULL);
83    LTC_ARGCHKVD(hash != NULL);
84 
85    h = hash;
86 
87    switch (size) {
88       default:
89          h[3] = ctx->s[0] & 0x0ff;
90          /* FALLTHROUGH */
91       case 3:
92          h[2] = (ctx->s[0] >> 8) & 0x0ff;
93          /* FALLTHROUGH */
94       case 2:
95          h[1] = ctx->s[1] & 0x0ff;
96          /* FALLTHROUGH */
97       case 1:
98          h[0] = (ctx->s[1] >> 8) & 0x0ff;
99          /* FALLTHROUGH */
100       case 0:
101          ;
102    }
103 }
104 
adler32_test(void)105 int adler32_test(void)
106 {
107 #ifndef LTC_TEST
108    return CRYPT_NOP;
109 #else
110    const void* in = "libtomcrypt";
111    const unsigned char adler32[] = { 0x1b, 0xe8, 0x04, 0xba };
112    unsigned char out[4];
113    adler32_state ctx;
114    adler32_init(&ctx);
115    adler32_update(&ctx, in, XSTRLEN(in));
116    adler32_finish(&ctx, out, 4);
117    if (compare_testvector(adler32, 4, out, 4, "adler32", 0)) {
118       return CRYPT_FAIL_TESTVECTOR;
119    }
120    return CRYPT_OK;
121 #endif
122 }
123 #endif
124