1*8411e6adSJerome Forissier /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2*8411e6adSJerome Forissier /* SPDX-License-Identifier: Unlicense */
35a913ee7SJerome Forissier #include "tomcrypt_private.h"
45a913ee7SJerome Forissier
55a913ee7SJerome Forissier /**
65a913ee7SJerome Forissier @file adler32.c
75a913ee7SJerome Forissier Adler-32 checksum algorithm
85a913ee7SJerome Forissier Written and placed in the public domain by Wei Dai
95a913ee7SJerome Forissier Adapted for libtomcrypt by Steffen Jaeckel
105a913ee7SJerome Forissier */
115a913ee7SJerome Forissier #ifdef LTC_ADLER32
125a913ee7SJerome Forissier
13*8411e6adSJerome Forissier static const unsigned long s_adler32_base = 65521;
145a913ee7SJerome Forissier
adler32_init(adler32_state * ctx)155a913ee7SJerome Forissier void adler32_init(adler32_state *ctx)
165a913ee7SJerome Forissier {
175a913ee7SJerome Forissier LTC_ARGCHKVD(ctx != NULL);
185a913ee7SJerome Forissier ctx->s[0] = 1;
195a913ee7SJerome Forissier ctx->s[1] = 0;
205a913ee7SJerome Forissier }
215a913ee7SJerome Forissier
adler32_update(adler32_state * ctx,const unsigned char * input,unsigned long length)225a913ee7SJerome Forissier void adler32_update(adler32_state *ctx, const unsigned char *input, unsigned long length)
235a913ee7SJerome Forissier {
245a913ee7SJerome Forissier unsigned long s1, s2;
255a913ee7SJerome Forissier
265a913ee7SJerome Forissier LTC_ARGCHKVD(ctx != NULL);
275a913ee7SJerome Forissier LTC_ARGCHKVD(input != NULL);
285a913ee7SJerome Forissier s1 = ctx->s[0];
295a913ee7SJerome Forissier s2 = ctx->s[1];
305a913ee7SJerome Forissier
315a913ee7SJerome Forissier if (length % 8 != 0) {
325a913ee7SJerome Forissier do {
335a913ee7SJerome Forissier s1 += *input++;
345a913ee7SJerome Forissier s2 += s1;
355a913ee7SJerome Forissier length--;
365a913ee7SJerome Forissier } while (length % 8 != 0);
375a913ee7SJerome Forissier
38*8411e6adSJerome Forissier if (s1 >= s_adler32_base) {
39*8411e6adSJerome Forissier s1 -= s_adler32_base;
405a913ee7SJerome Forissier }
41*8411e6adSJerome Forissier s2 %= s_adler32_base;
425a913ee7SJerome Forissier }
435a913ee7SJerome Forissier
445a913ee7SJerome Forissier while (length > 0) {
455a913ee7SJerome Forissier s1 += input[0];
465a913ee7SJerome Forissier s2 += s1;
475a913ee7SJerome Forissier s1 += input[1];
485a913ee7SJerome Forissier s2 += s1;
495a913ee7SJerome Forissier s1 += input[2];
505a913ee7SJerome Forissier s2 += s1;
515a913ee7SJerome Forissier s1 += input[3];
525a913ee7SJerome Forissier s2 += s1;
535a913ee7SJerome Forissier s1 += input[4];
545a913ee7SJerome Forissier s2 += s1;
555a913ee7SJerome Forissier s1 += input[5];
565a913ee7SJerome Forissier s2 += s1;
575a913ee7SJerome Forissier s1 += input[6];
585a913ee7SJerome Forissier s2 += s1;
595a913ee7SJerome Forissier s1 += input[7];
605a913ee7SJerome Forissier s2 += s1;
615a913ee7SJerome Forissier
625a913ee7SJerome Forissier length -= 8;
635a913ee7SJerome Forissier input += 8;
645a913ee7SJerome Forissier
65*8411e6adSJerome Forissier if (s1 >= s_adler32_base) {
66*8411e6adSJerome Forissier s1 -= s_adler32_base;
675a913ee7SJerome Forissier }
68*8411e6adSJerome Forissier s2 %= s_adler32_base;
695a913ee7SJerome Forissier }
705a913ee7SJerome Forissier
71*8411e6adSJerome Forissier LTC_ARGCHKVD(s1 < s_adler32_base);
72*8411e6adSJerome Forissier LTC_ARGCHKVD(s2 < s_adler32_base);
735a913ee7SJerome Forissier
745a913ee7SJerome Forissier ctx->s[0] = (unsigned short)s1;
755a913ee7SJerome Forissier ctx->s[1] = (unsigned short)s2;
765a913ee7SJerome Forissier }
775a913ee7SJerome Forissier
adler32_finish(const adler32_state * ctx,void * hash,unsigned long size)785a913ee7SJerome Forissier void adler32_finish(const adler32_state *ctx, void *hash, unsigned long size)
795a913ee7SJerome Forissier {
805a913ee7SJerome Forissier unsigned char* h;
815a913ee7SJerome Forissier
825a913ee7SJerome Forissier LTC_ARGCHKVD(ctx != NULL);
835a913ee7SJerome Forissier LTC_ARGCHKVD(hash != NULL);
845a913ee7SJerome Forissier
855a913ee7SJerome Forissier h = hash;
865a913ee7SJerome Forissier
875a913ee7SJerome Forissier switch (size) {
885a913ee7SJerome Forissier default:
895a913ee7SJerome Forissier h[3] = ctx->s[0] & 0x0ff;
905a913ee7SJerome Forissier /* FALLTHROUGH */
915a913ee7SJerome Forissier case 3:
925a913ee7SJerome Forissier h[2] = (ctx->s[0] >> 8) & 0x0ff;
935a913ee7SJerome Forissier /* FALLTHROUGH */
945a913ee7SJerome Forissier case 2:
955a913ee7SJerome Forissier h[1] = ctx->s[1] & 0x0ff;
965a913ee7SJerome Forissier /* FALLTHROUGH */
975a913ee7SJerome Forissier case 1:
985a913ee7SJerome Forissier h[0] = (ctx->s[1] >> 8) & 0x0ff;
995a913ee7SJerome Forissier /* FALLTHROUGH */
1005a913ee7SJerome Forissier case 0:
1015a913ee7SJerome Forissier ;
1025a913ee7SJerome Forissier }
1035a913ee7SJerome Forissier }
1045a913ee7SJerome Forissier
adler32_test(void)1055a913ee7SJerome Forissier int adler32_test(void)
1065a913ee7SJerome Forissier {
1075a913ee7SJerome Forissier #ifndef LTC_TEST
1085a913ee7SJerome Forissier return CRYPT_NOP;
1095a913ee7SJerome Forissier #else
1105a913ee7SJerome Forissier const void* in = "libtomcrypt";
1115a913ee7SJerome Forissier const unsigned char adler32[] = { 0x1b, 0xe8, 0x04, 0xba };
1125a913ee7SJerome Forissier unsigned char out[4];
1135a913ee7SJerome Forissier adler32_state ctx;
1145a913ee7SJerome Forissier adler32_init(&ctx);
115*8411e6adSJerome Forissier adler32_update(&ctx, in, XSTRLEN(in));
1165a913ee7SJerome Forissier adler32_finish(&ctx, out, 4);
1175a913ee7SJerome Forissier if (compare_testvector(adler32, 4, out, 4, "adler32", 0)) {
1185a913ee7SJerome Forissier return CRYPT_FAIL_TESTVECTOR;
1195a913ee7SJerome Forissier }
1205a913ee7SJerome Forissier return CRYPT_OK;
1215a913ee7SJerome Forissier #endif
1225a913ee7SJerome Forissier }
1235a913ee7SJerome Forissier #endif
124