From ceaa9f9d20f5db8b36d275fe65de43b95b090fc1 Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Wed, 31 Jul 2013 14:30:04 +0300 Subject: Prepare for Signature Version 4. * lib/hmac_sha256.c: New file. * lib/sha256.c: New file. * lib/sha256.h: New file. * lib/Makefile.am (libeclat_a_SOURCES): Add new files. * lib/libeclat.h (hmac_sha256): New proto. (eclat_query_signature): Rename to eclat_query_sign, take signature version as argument. (eclat_encode_devmap): Remove prototype. * lib/reqsign.c: Use HMAC256 * src/config.c (eclat_kw): New keyword: signature-version, * src/devmap.c (eclat_encode_devmap): Bugfixes. Translate snapshot ids. * src/eclat.c (signature_version): New variable. * src/eclat.h (signature_version): New proto. (eclat_encode_devmap): New proto. * src/util.c (eclat_send_query): Use eclat_query_sign. * tests/hmac01.at: Update. * tests/hmac02.at: Update. * tests/hmac03.at: Update. * tests/thmac.c: Use HMAC256 --- lib/Makefile.am | 3 + lib/hmac_sha256.c | 77 ++++++++ lib/libeclat.h | 8 +- lib/reqsign.c | 46 ++++- lib/sha256.c | 569 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/sha256.h | 91 +++++++++ src/config.c | 5 +- src/devmap.c | 43 +++-- src/eclat.c | 1 + src/eclat.h | 2 + src/util.c | 2 +- tests/hmac01.at | 2 +- tests/hmac02.at | 2 +- tests/hmac03.at | 2 +- tests/thmac.c | 5 +- 15 files changed, 824 insertions(+), 34 deletions(-) create mode 100644 lib/hmac_sha256.c create mode 100644 lib/sha256.c create mode 100644 lib/sha256.h diff --git a/lib/Makefile.am b/lib/Makefile.am index 380db7a..0f95e27 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -45,6 +45,7 @@ libeclat_a_SOURCES=\ getans.c\ getyn.c\ hmac_sha1.c\ + hmac_sha256.c\ libeclat.h\ map.c\ q2url.c\ @@ -55,6 +56,8 @@ libeclat_a_SOURCES=\ reqsign.c\ sha1.c\ sha1.h\ + sha256.c\ + sha256.h\ urlencode.c\ xmltree.c\ $(maps) diff --git a/lib/hmac_sha256.c b/lib/hmac_sha256.c new file mode 100644 index 0000000..be7f50a --- /dev/null +++ b/lib/hmac_sha256.c @@ -0,0 +1,77 @@ +/* This file is part of Eclat + Copyright (C) 2012, 2013 Sergey Poznyakoff + + Eclat is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + Eclat is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Eclat. If not, see . */ + +#include +#include "libeclat.h" +#include "sha256.h" +#include + +#define IPAD 0x36 +#define OPAD 0x5c + +void +hmac_sha256(const void *text, size_t textlen, + const void *key, size_t keylen, + void *digest) +{ + size_t i; + struct sha256_ctx ctx; + char innerhash[SHA256_DIGEST_SIZE]; + char keybuf[SHA256_DIGEST_SIZE]; + unsigned char ipad[64]; /* inner padding - key ^ ipad[64] */ + unsigned char opad[64]; /* outer padding - key ^ opad[64] */ + unsigned char *kp = (unsigned char *)key; + + /* if key is longer than 64 bytes reset it to key=SHA256(key) */ + if (keylen > 64) { + struct sha256_ctx keyhash; + + sha256_init_ctx(&keyhash); + sha256_process_bytes(key, keylen, &keyhash); + sha256_finish_ctx(&keyhash, keybuf); + key = keybuf; + keylen = sizeof(keybuf); + } + + /* Compute SHA256(K XOR opad, SHA256(K XOR ipad, text)), + where + K is an key, padded to 64 bytes with zeros, + ipad and opad are the respective defines above repeated 64 times + text is the text argument (textlen bytes long) + */ + memset(ipad, IPAD, sizeof(ipad)); + memset(opad, OPAD, sizeof(opad)); + + for (i = 0; i < keylen; i++, kp++) { + ipad[i] ^= *kp; + opad[i] ^= *kp; + } + + /* Compute inner hash */ + sha256_init_ctx(&ctx); + sha256_process_block(ipad, sizeof(ipad), &ctx); + sha256_process_bytes(text, textlen, &ctx); + sha256_finish_ctx(&ctx, innerhash); + + /* Compute outer hash */ + sha256_init_ctx(&ctx); + sha256_process_block(opad, sizeof(opad), &ctx); + sha256_process_bytes(innerhash, sizeof(innerhash), &ctx); + sha256_finish_ctx(&ctx, digest); +} + + + diff --git a/lib/libeclat.h b/lib/libeclat.h index 0e8868b..32deba3 100644 --- a/lib/libeclat.h +++ b/lib/libeclat.h @@ -54,6 +54,10 @@ int debug_register(char *name); void hmac_sha1(const void *text, size_t textlen, const void *key, size_t keylen, void *digest); +void hmac_sha256(const void *text, size_t textlen, + const void *key, size_t keylen, + void *digest); + void urlencode(const char *input, size_t len, char **poutput, size_t *poutlen); @@ -88,14 +92,12 @@ void eclat_query_free(struct ec2_query *); void eclat_query_add_param(struct ec2_query *q, const char *name, const char *value); -void eclat_query_signature(struct ec2_query *req, char *secret); +void eclat_query_sign(struct ec2_query *req, char *secret, char *version); char *eclat_query_to_url(struct ec2_query *req, char **post_params); void eclat_query_encode(struct ec2_query *q); -void eclat_encode_devmap(struct ec2_query *q, struct grecs_list *list); - typedef struct eclat_partial_tree *eclat_partial_tree_t; diff --git a/lib/reqsign.c b/lib/reqsign.c index a8a4e5e..893e4d7 100644 --- a/lib/reqsign.c +++ b/lib/reqsign.c @@ -18,6 +18,7 @@ #include #include #include "libeclat.h" +#include "sha256.h" #include "grecs.h" struct pname { @@ -42,15 +43,15 @@ compnames(const void *a, const void *b) return strcmp(*ac, *bc); } -void -eclat_query_signature(struct ec2_query *req, char *secret) +static void +querysign2(struct ec2_query *req, char *secret) { char **pnames; size_t i, n; struct grecs_txtacc *acc; struct pname pn; char *str; - char digest[20]; + char digest[SHA256_DIGEST_SIZE]; size_t siglen; const char *verb; char tsbuf[22]; @@ -59,7 +60,7 @@ eclat_query_signature(struct ec2_query *req, char *secret) acc = grecs_txtacc_create(); /* Add default parameters */ - eclat_query_add_param(req, "SignatureMethod", "HmacSHA1"); + eclat_query_add_param(req, "SignatureMethod", "HmacSHA256"); eclat_query_add_param(req, "SignatureVersion", "2"); time(&t); @@ -103,7 +104,7 @@ eclat_query_signature(struct ec2_query *req, char *secret) grecs_txtacc_grow_char(acc, 0); str = grecs_txtacc_finish(acc, 0); - hmac_sha1(str, strlen(str), secret, strlen(secret), digest); + hmac_sha256(str, strlen(str), secret, strlen(secret), digest); eclat_base64_encode((unsigned char *)digest, sizeof(digest), (unsigned char**) &req->signature, &siglen); @@ -117,3 +118,38 @@ eclat_query_signature(struct ec2_query *req, char *secret) eclat_query_add_param(req, "Expires", tsbuf); */ } + +static void +querysign4(struct ec2_query *req, char *secret) +{ + abort(); +} + + +struct qsimpl { + char *qs_version; + void (*qs_fun)(struct ec2_query *, char *); +}; + +static struct qsimpl qstab[] = { + { "2", querysign2 }, + { "4", querysign4 }, + { NULL } +}; + +void +eclat_query_sign(struct ec2_query *req, char *secret, char *version) +{ + struct qsimpl *qs; + + for (qs = qstab; qs->qs_version && strcmp(qs->qs_version, version); + qs++) + ; + + if (qs->qs_version) + qs->qs_fun(req, secret); + else { + err("INTERNAL ERROR: unsupported version %s", version); + abort(); + } +} diff --git a/lib/sha256.c b/lib/sha256.c new file mode 100644 index 0000000..4b2cee3 --- /dev/null +++ b/lib/sha256.c @@ -0,0 +1,569 @@ +/* sha256.c - Functions to compute SHA256 and SHA224 message digest of files or + memory blocks according to the NIST specification FIPS-180-2. + + Copyright (C) 2005-2006, 2008-2013 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* Written by David Madore, considerably copypasting from + Scott G. Miller's sha1.c +*/ + +#include + +#include "sha256.h" + +#include +#include +#include +#include + +#if USE_UNLOCKED_IO +# include "unlocked-io.h" +#endif + +#ifdef WORDS_BIGENDIAN +# define SWAP(n) (n) +#else +# define SWAP(n) \ + (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) +#endif + +#define BLOCKSIZE 32768 +#if BLOCKSIZE % 64 != 0 +# error "invalid BLOCKSIZE" +#endif + +/* This array contains the bytes used to pad the buffer to the next + 64-byte boundary. */ +static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; + + +/* + Takes a pointer to a 256 bit block of data (eight 32 bit ints) and + initializes it to the start constants of the SHA256 algorithm. This + must be called before using hash in the call to sha256_hash +*/ +void +sha256_init_ctx (struct sha256_ctx *ctx) +{ + ctx->state[0] = 0x6a09e667UL; + ctx->state[1] = 0xbb67ae85UL; + ctx->state[2] = 0x3c6ef372UL; + ctx->state[3] = 0xa54ff53aUL; + ctx->state[4] = 0x510e527fUL; + ctx->state[5] = 0x9b05688cUL; + ctx->state[6] = 0x1f83d9abUL; + ctx->state[7] = 0x5be0cd19UL; + + ctx->total[0] = ctx->total[1] = 0; + ctx->buflen = 0; +} + +void +sha224_init_ctx (struct sha256_ctx *ctx) +{ + ctx->state[0] = 0xc1059ed8UL; + ctx->state[1] = 0x367cd507UL; + ctx->state[2] = 0x3070dd17UL; + ctx->state[3] = 0xf70e5939UL; + ctx->state[4] = 0xffc00b31UL; + ctx->state[5] = 0x68581511UL; + ctx->state[6] = 0x64f98fa7UL; + ctx->state[7] = 0xbefa4fa4UL; + + ctx->total[0] = ctx->total[1] = 0; + ctx->buflen = 0; +} + +/* Copy the value from v into the memory location pointed to by *cp, + If your architecture allows unaligned access this is equivalent to + * (uint32_t *) cp = v */ +static void +set_uint32 (char *cp, uint32_t v) +{ + memcpy (cp, &v, sizeof v); +} + +/* Put result from CTX in first 32 bytes following RESBUF. The result + must be in little endian byte order. */ +void * +sha256_read_ctx (const struct sha256_ctx *ctx, void *resbuf) +{ + int i; + char *r = resbuf; + + for (i = 0; i < 8; i++) + set_uint32 (r + i * sizeof ctx->state[0], SWAP (ctx->state[i])); + + return resbuf; +} + +void * +sha224_read_ctx (const struct sha256_ctx *ctx, void *resbuf) +{ + int i; + char *r = resbuf; + + for (i = 0; i < 7; i++) + set_uint32 (r + i * sizeof ctx->state[0], SWAP (ctx->state[i])); + + return resbuf; +} + +/* Process the remaining bytes in the internal buffer and the usual + prolog according to the standard and write the result to RESBUF. */ +static void +sha256_conclude_ctx (struct sha256_ctx *ctx) +{ + /* Take yet unprocessed bytes into account. */ + size_t bytes = ctx->buflen; + size_t size = (bytes < 56) ? 64 / 4 : 64 * 2 / 4; + + /* Now count remaining bytes. */ + ctx->total[0] += bytes; + if (ctx->total[0] < bytes) + ++ctx->total[1]; + + /* Put the 64-bit file length in *bits* at the end of the buffer. + Use set_uint32 rather than a simple assignment, to avoid risk of + unaligned access. */ + set_uint32 ((char *) &ctx->buffer[size - 2], + SWAP ((ctx->total[1] << 3) | (ctx->total[0] >> 29))); + set_uint32 ((char *) &ctx->buffer[size - 1], + SWAP (ctx->total[0] << 3)); + + memcpy (&((char *) ctx->buffer)[bytes], fillbuf, (size - 2) * 4 - bytes); + + /* Process last bytes. */ + sha256_process_block (ctx->buffer, size * 4, ctx); +} + +void * +sha256_finish_ctx (struct sha256_ctx *ctx, void *resbuf) +{ + sha256_conclude_ctx (ctx); + return sha256_read_ctx (ctx, resbuf); +} + +void * +sha224_finish_ctx (struct sha256_ctx *ctx, void *resbuf) +{ + sha256_conclude_ctx (ctx); + return sha224_read_ctx (ctx, resbuf); +} + +/* Compute SHA256 message digest for bytes read from STREAM. The + resulting message digest number will be written into the 32 bytes + beginning at RESBLOCK. */ +int +sha256_stream (FILE *stream, void *resblock) +{ + struct sha256_ctx ctx; + size_t sum; + + char *buffer = malloc (BLOCKSIZE + 72); + if (!buffer) + return 1; + + /* Initialize the computation context. */ + sha256_init_ctx (&ctx); + + /* Iterate over full file contents. */ + while (1) + { + /* We read the file in blocks of BLOCKSIZE bytes. One call of the + computation function processes the whole buffer so that with the + next round of the loop another block can be read. */ + size_t n; + sum = 0; + + /* Read block. Take care for partial reads. */ + while (1) + { + n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); + + sum += n; + + if (sum == BLOCKSIZE) + break; + + if (n == 0) + { + /* Check for the error flag IFF N == 0, so that we don't + exit the loop after a partial read due to e.g., EAGAIN + or EWOULDBLOCK. */ + if (ferror (stream)) + { + free (buffer); + return 1; + } + goto process_partial_block; + } + + /* We've read at least one byte, so ignore errors. But always + check for EOF, since feof may be true even though N > 0. + Otherwise, we could end up calling fread after EOF. */ + if (feof (stream)) + goto process_partial_block; + } + + /* Process buffer with BLOCKSIZE bytes. Note that + BLOCKSIZE % 64 == 0 + */ + sha256_process_block (buffer, BLOCKSIZE, &ctx); + } + + process_partial_block:; + + /* Process any remaining bytes. */ + if (sum > 0) + sha256_process_bytes (buffer, sum, &ctx); + + /* Construct result in desired memory. */ + sha256_finish_ctx (&ctx, resblock); + free (buffer); + return 0; +} + +/* FIXME: Avoid code duplication */ +int +sha224_stream (FILE *stream, void *resblock) +{ + struct sha256_ctx ctx; + size_t sum; + + char *buffer = malloc (BLOCKSIZE + 72); + if (!buffer) + return 1; + + /* Initialize the computation context. */ + sha224_init_ctx (&ctx); + + /* Iterate over full file contents. */ + while (1) + { + /* We read the file in blocks of BLOCKSIZE bytes. One call of the + computation function processes the whole buffer so that with the + next round of the loop another block can be read. */ + size_t n; + sum = 0; + + /* Read block. Take care for partial reads. */ + while (1) + { + n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); + + sum += n; + + if (sum == BLOCKSIZE) + break; + + if (n == 0) + { + /* Check for the error flag IFF N == 0, so that we don't + exit the loop after a partial read due to e.g., EAGAIN + or EWOULDBLOCK. */ + if (ferror (stream)) + { + free (buffer); + return 1; + } + goto process_partial_block; + } + + /* We've read at least one byte, so ignore errors. But always + check for EOF, since feof may be true even though N > 0. + Otherwise, we could end up calling fread after EOF. */ + if (feof (stream)) + goto process_partial_block; + } + + /* Process buffer with BLOCKSIZE bytes. Note that + BLOCKSIZE % 64 == 0 + */ + sha256_process_block (buffer, BLOCKSIZE, &ctx); + } + + process_partial_block:; + + /* Process any remaining bytes. */ + if (sum > 0) + sha256_process_bytes (buffer, sum, &ctx); + + /* Construct result in desired memory. */ + sha224_finish_ctx (&ctx, resblock); + free (buffer); + return 0; +} + +/* Compute SHA512 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +void * +sha256_buffer (const char *buffer, size_t len, void *resblock) +{ + struct sha256_ctx ctx; + + /* Initialize the computation context. */ + sha256_init_ctx (&ctx); + + /* Process whole buffer but last len % 64 bytes. */ + sha256_process_bytes (buffer, len, &ctx); + + /* Put result in desired memory area. */ + return sha256_finish_ctx (&ctx, resblock); +} + +void * +sha224_buffer (const char *buffer, size_t len, void *resblock) +{ + struct sha256_ctx ctx; + + /* Initialize the computation context. */ + sha224_init_ctx (&ctx); + + /* Process whole buffer but last len % 64 bytes. */ + sha256_process_bytes (buffer, len, &ctx); + + /* Put result in desired memory area. */ + return sha224_finish_ctx (&ctx, resblock); +} + +void +sha256_process_bytes (const void *buffer, size_t len, struct sha256_ctx *ctx) +{ + /* When we already have some bits in our internal buffer concatenate + both inputs first. */ + if (ctx->buflen != 0) + { + size_t left_over = ctx->buflen; + size_t add = 128 - left_over > len ? len : 128 - left_over; + + memcpy (&((char *) ctx->buffer)[left_over], buffer, add); + ctx->buflen += add; + + if (ctx->buflen > 64) + { + sha256_process_block (ctx->buffer, ctx->buflen & ~63, ctx); + + ctx->buflen &= 63; + /* The regions in the following copy operation cannot overlap. */ + memcpy (ctx->buffer, + &((char *) ctx->buffer)[(left_over + add) & ~63], + ctx->buflen); + } + + buffer = (const char *) buffer + add; + len -= add; + } + + /* Process available complete blocks. */ + if (len >= 64) + { +#if !_STRING_ARCH_unaligned +# define UNALIGNED_P(p) ((uintptr_t) (p) % alignof (uint32_t) != 0) + if (UNALIGNED_P (buffer)) + while (len > 64) + { + sha256_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx); + buffer = (const char *) buffer + 64; + len -= 64; + } + else +#endif + { + sha256_process_block (buffer, len & ~63, ctx); + buffer = (const char *) buffer + (len & ~63); + len &= 63; + } + } + + /* Move remaining bytes in internal buffer. */ + if (len > 0) + { + size_t left_over = ctx->buflen; + + memcpy (&((char *) ctx->buffer)[left_over], buffer, len); + left_over += len; + if (left_over >= 64) + { + sha256_process_block (ctx->buffer, 64, ctx); + left_over -= 64; + memcpy (ctx->buffer, &ctx->buffer[16], left_over); + } + ctx->buflen = left_over; + } +} + +/* --- Code below is the primary difference between sha1.c and sha256.c --- */ + +/* SHA256 round constants */ +#define K(I) sha256_round_constants[I] +static const uint32_t sha256_round_constants[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, + 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, + 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, + 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, + 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, + 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, + 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, + 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, + 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, + 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, + 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, + 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, + 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL, +}; + +/* Round functions. */ +#define F2(A,B,C) ( ( A & B ) | ( C & ( A | B ) ) ) +#define F1(E,F,G) ( G ^ ( E & ( F ^ G ) ) ) + +/* Process LEN bytes of BUFFER, accumulating context into CTX. + It is assumed that LEN % 64 == 0. + Most of this code comes from GnuPG's cipher/sha1.c. */ + +void +sha256_process_block (const void *buffer, size_t len, struct sha256_ctx *ctx) +{ + const uint32_t *words = buffer; + size_t nwords = len / sizeof (uint32_t); + const uint32_t *endp = words + nwords; + uint32_t x[16]; + uint32_t a = ctx->state[0]; + uint32_t b = ctx->state[1]; + uint32_t c = ctx->state[2]; + uint32_t d = ctx->state[3]; + uint32_t e = ctx->state[4]; + uint32_t f = ctx->state[5]; + uint32_t g = ctx->state[6]; + uint32_t h = ctx->state[7]; + uint32_t lolen = len; + + /* First increment the byte count. FIPS PUB 180-2 specifies the possible + length of the file up to 2^64 bits. Here we only compute the + number of bytes. Do a double word increment. */ + ctx->total[0] += lolen; + ctx->total[1] += (len >> 31 >> 1) + (ctx->total[0] < lolen); + +#define rol(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) +#define S0(x) (rol(x,25)^rol(x,14)^(x>>3)) +#define S1(x) (rol(x,15)^rol(x,13)^(x>>10)) +#define SS0(x) (rol(x,30)^rol(x,19)^rol(x,10)) +#define SS1(x) (rol(x,26)^rol(x,21)^rol(x,7)) + +#define M(I) ( tm = S1(x[(I-2)&0x0f]) + x[(I-7)&0x0f] \ + + S0(x[(I-15)&0x0f]) + x[I&0x0f] \ + , x[I&0x0f] = tm ) + +#define R(A,B,C,D,E,F,G,H,K,M) do { t0 = SS0(A) + F2(A,B,C); \ + t1 = H + SS1(E) \ + + F1(E,F,G) \ + + K \ + + M; \ + D += t1; H = t0 + t1; \ + } while(0) + + while (words < endp) + { + uint32_t tm; + uint32_t t0, t1; + int t; + /* FIXME: see sha1.c for a better implementation. */ + for (t = 0; t < 16; t++) + { + x[t] = SWAP (*words); + words++; + } + + R( a, b, c, d, e, f, g, h, K( 0), x[ 0] ); + R( h, a, b, c, d, e, f, g, K( 1), x[ 1] ); + R( g, h, a, b, c, d, e, f, K( 2), x[ 2] ); + R( f, g, h, a, b, c, d, e, K( 3), x[ 3] ); + R( e, f, g, h, a, b, c, d, K( 4), x[ 4] ); + R( d, e, f, g, h, a, b, c, K( 5), x[ 5] ); + R( c, d, e, f, g, h, a, b, K( 6), x[ 6] ); + R( b, c, d, e, f, g, h, a, K( 7), x[ 7] ); + R( a, b, c, d, e, f, g, h, K( 8), x[ 8] ); + R( h, a, b, c, d, e, f, g, K( 9), x[ 9] ); + R( g, h, a, b, c, d, e, f, K(10), x[10] ); + R( f, g, h, a, b, c, d, e, K(11), x[11] ); + R( e, f, g, h, a, b, c, d, K(12), x[12] ); + R( d, e, f, g, h, a, b, c, K(13), x[13] ); + R( c, d, e, f, g, h, a, b, K(14), x[14] ); + R( b, c, d, e, f, g, h, a, K(15), x[15] ); + R( a, b, c, d, e, f, g, h, K(16), M(16) ); + R( h, a, b, c, d, e, f, g, K(17), M(17) ); + R( g, h, a, b, c, d, e, f, K(18), M(18) ); + R( f, g, h, a, b, c, d, e, K(19), M(19) ); + R( e, f, g, h, a, b, c, d, K(20), M(20) ); + R( d, e, f, g, h, a, b, c, K(21), M(21) ); + R( c, d, e, f, g, h, a, b, K(22), M(22) ); + R( b, c, d, e, f, g, h, a, K(23), M(23) ); + R( a, b, c, d, e, f, g, h, K(24), M(24) ); + R( h, a, b, c, d, e, f, g, K(25), M(25) ); + R( g, h, a, b, c, d, e, f, K(26), M(26) ); + R( f, g, h, a, b, c, d, e, K(27), M(27) ); + R( e, f, g, h, a, b, c, d, K(28), M(28) ); + R( d, e, f, g, h, a, b, c, K(29), M(29) ); + R( c, d, e, f, g, h, a, b, K(30), M(30) ); + R( b, c, d, e, f, g, h, a, K(31), M(31) ); + R( a, b, c, d, e, f, g, h, K(32), M(32) ); + R( h, a, b, c, d, e, f, g, K(33), M(33) ); + R( g, h, a, b, c, d, e, f, K(34), M(34) ); + R( f, g, h, a, b, c, d, e, K(35), M(35) ); + R( e, f, g, h, a, b, c, d, K(36), M(36) ); + R( d, e, f, g, h, a, b, c, K(37), M(37) ); + R( c, d, e, f, g, h, a, b, K(38), M(38) ); + R( b, c, d, e, f, g, h, a, K(39), M(39) ); + R( a, b, c, d, e, f, g, h, K(40), M(40) ); + R( h, a, b, c, d, e, f, g, K(41), M(41) ); + R( g, h, a, b, c, d, e, f, K(42), M(42) ); + R( f, g, h, a, b, c, d, e, K(43), M(43) ); + R( e, f, g, h, a, b, c, d, K(44), M(44) ); + R( d, e, f, g, h, a, b, c, K(45), M(45) ); + R( c, d, e, f, g, h, a, b, K(46), M(46) ); + R( b, c, d, e, f, g, h, a, K(47), M(47) ); + R( a, b, c, d, e, f, g, h, K(48), M(48) ); + R( h, a, b, c, d, e, f, g, K(49), M(49) ); + R( g, h, a, b, c, d, e, f, K(50), M(50) ); + R( f, g, h, a, b, c, d, e, K(51), M(51) ); + R( e, f, g, h, a, b, c, d, K(52), M(52) ); + R( d, e, f, g, h, a, b, c, K(53), M(53) ); + R( c, d, e, f, g, h, a, b, K(54), M(54) ); + R( b, c, d, e, f, g, h, a, K(55), M(55) ); + R( a, b, c, d, e, f, g, h, K(56), M(56) ); + R( h, a, b, c, d, e, f, g, K(57), M(57) ); + R( g, h, a, b, c, d, e, f, K(58), M(58) ); + R( f, g, h, a, b, c, d, e, K(59), M(59) ); + R( e, f, g, h, a, b, c, d, K(60), M(60) ); + R( d, e, f, g, h, a, b, c, K(61), M(61) ); + R( c, d, e, f, g, h, a, b, K(62), M(62) ); + R( b, c, d, e, f, g, h, a, K(63), M(63) ); + + a = ctx->state[0] += a; + b = ctx->state[1] += b; + c = ctx->state[2] += c; + d = ctx->state[3] += d; + e = ctx->state[4] += e; + f = ctx->state[5] += f; + g = ctx->state[6] += g; + h = ctx->state[7] += h; + } +} diff --git a/lib/sha256.h b/lib/sha256.h new file mode 100644 index 0000000..44060a7 --- /dev/null +++ b/lib/sha256.h @@ -0,0 +1,91 @@ +/* Declarations of functions and data types used for SHA256 and SHA224 sum + library functions. + Copyright (C) 2005-2006, 2008-2013 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#ifndef ECLAT_SHA256_H +# define ECLAT_SHA256_H 1 + +# include +# include + +# ifdef __cplusplus +extern "C" { +# endif + +/* Structure to save state of computation between the single steps. */ +struct sha256_ctx +{ + uint32_t state[8]; + + uint32_t total[2]; + size_t buflen; + uint32_t buffer[32]; +}; + +enum { SHA224_DIGEST_SIZE = 224 / 8 }; +enum { SHA256_DIGEST_SIZE = 256 / 8 }; + +/* Initialize structure containing state of computation. */ +extern void sha256_init_ctx (struct sha256_ctx *ctx); +extern void sha224_init_ctx (struct sha256_ctx *ctx); + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is necessary that LEN is a multiple of 64!!! */ +extern void sha256_process_block (const void *buffer, size_t len, + struct sha256_ctx *ctx); + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is NOT required that LEN is a multiple of 64. */ +extern void sha256_process_bytes (const void *buffer, size_t len, + struct sha256_ctx *ctx); + +/* Process the remaining bytes in the buffer and put result from CTX + in first 32 (28) bytes following RESBUF. The result is always in little + endian byte order, so that a byte-wise output yields to the wanted + ASCII representation of the message digest. */ +extern void *sha256_finish_ctx (struct sha256_ctx *ctx, void *resbuf); +extern void *sha224_finish_ctx (struct sha256_ctx *ctx, void *resbuf); + + +/* Put result from CTX in first 32 (28) bytes following RESBUF. The result is + always in little endian byte order, so that a byte-wise output yields + to the wanted ASCII representation of the message digest. */ +extern void *sha256_read_ctx (const struct sha256_ctx *ctx, void *resbuf); +extern void *sha224_read_ctx (const struct sha256_ctx *ctx, void *resbuf); + + +/* Compute SHA256 (SHA224) message digest for bytes read from STREAM. The + resulting message digest number will be written into the 32 (28) bytes + beginning at RESBLOCK. */ +extern int sha256_stream (FILE *stream, void *resblock); +extern int sha224_stream (FILE *stream, void *resblock); + +/* Compute SHA256 (SHA224) message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +extern void *sha256_buffer (const char *buffer, size_t len, void *resblock); +extern void *sha224_buffer (const char *buffer, size_t len, void *resblock); + +# ifdef __cplusplus +} +# endif + +#endif diff --git a/src/config.c b/src/config.c index a29be0d..78f0129 100644 --- a/src/config.c +++ b/src/config.c @@ -260,7 +260,10 @@ static struct grecs_keyword eclat_kw[] = { grecs_type_string, GRECS_DFLT, &endpoint }, { "region", " ", "Define a region", - grecs_type_string, GRECS_MULT, NULL, 0, cb_region }, + grecs_type_string, GRECS_MULT, NULL, 0, cb_region }, + { "signature-version", "version", + "Signature version", + grecs_type_string, GRECS_DFLT, &signature_version }, { "access-file", "file", "Specify a file containing `accessID:accessKey' pairs", grecs_type_string, GRECS_DFLT, &access_file_name }, diff --git a/src/devmap.c b/src/devmap.c index 2e0cff4..7cd63df 100644 --- a/src/devmap.c +++ b/src/devmap.c @@ -14,13 +14,7 @@ You should have received a copy of the GNU General Public License along with Eclat. If not, see . */ -#include -#include -#include -#include -#include "libeclat.h" -#include "wordsplit.h" -#include "grecs.h" +#include "eclat.h" static int isnumstr(const char *p) @@ -76,22 +70,31 @@ eclat_encode_devmap(struct ec2_query *q, struct grecs_list *list) p, wordsplit_strerror(&ws)); if (ws.ws_wordc == 1) { - if (strncmp(ws.ws_wordv[0], "snap-", 5) == 0) { - grecs_asprintf(&bufptr, &bufsize, - "BlockDeviceMapping.%d." - "Ebs.SnapshotId", - i); - } else if (isnumstr(ws.ws_wordv[0])) { + if (isnumstr(ws.ws_wordv[0])) { grecs_asprintf(&bufptr, &bufsize, "BlockDeviceMapping.%d." "Ebs.VolumeSize", i); - } else - die(EX_USAGE, - "unrecognized word \"%s\", " - "expected either a snapshot ID, " - "or disk size", - ws.ws_wordv[0]); + } else { + translate_ids(1, &ws.ws_wordv[0], + MAP_SNAPSHOT); + if (strncmp(ws.ws_wordv[0], + "snap-", 5) == 0) { + grecs_asprintf(&bufptr, + &bufsize, + "BlockDeviceMapping.%d." + "Ebs.SnapshotId", + i); + } else { + die(EX_USAGE, + "unrecognized word \"%s\", " + "expected either a " + "snapshot ID, " + "or disk size, " + "or a device-specification", + ws.ws_wordv[0]); + } + } eclat_query_add_param(q, bufptr, ws.ws_wordv[0]); } else if (ws.ws_wordc < 2) { @@ -156,6 +159,8 @@ eclat_encode_devmap(struct ec2_query *q, struct grecs_list *list) eclat_query_add_param(q, bufptr, ws.ws_wordv[2]); } + case 2: + break; } wordsplit_free(&ws); } diff --git a/src/eclat.c b/src/eclat.c index 5523f0d..063accb 100644 --- a/src/eclat.c +++ b/src/eclat.c @@ -23,6 +23,7 @@ int match_command_mode; int preprocess_only = 0; char *endpoint = "ec2.amazonaws.com"; +char *signature_version = "2"; char *access_key; char *secret_key; char *region_name; diff --git a/src/eclat.h b/src/eclat.h index 3ece7fd..acf4c2d 100644 --- a/src/eclat.h +++ b/src/eclat.h @@ -40,6 +40,7 @@ #define ECLAT_DEBCAT_FORLAN 5 extern char *endpoint; +extern char *signature_version; extern int use_ssl; extern int ssl_verify_peer; extern char *ssl_ca_file; @@ -193,6 +194,7 @@ int get_scr_cols(void); void translate_ids(int argc, char **argv, const char *map); void translate_resource_ids(int argc, char **argv); +void eclat_encode_devmap(struct ec2_query *q, struct grecs_list *list); int get_access_creds(const char *id, char **access_key_ptr, char **secret_key_ptr); diff --git a/src/util.c b/src/util.c index 7760ead..49970f1 100644 --- a/src/util.c +++ b/src/util.c @@ -225,7 +225,7 @@ eclat_send_query(CURL *curl, struct ec2_query *q) eclat_query_add_param(q, "AWSAccessKeyId", access_key); - eclat_query_signature(q, secret_key); + eclat_query_sign(q, secret_key, signature_version); url = eclat_query_to_url(q, NULL); debug(ECLAT_DEBCAT_MAIN, 1, ("using URL: %s", url)); diff --git a/tests/hmac01.at b/tests/hmac01.at index f0aba02..2706dd9 100644 --- a/tests/hmac01.at +++ b/tests/hmac01.at @@ -19,7 +19,7 @@ AT_KEYWORDS([hmac hmac01]) AT_CHECK([thmac 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b "Hi There"], [0], -[0x675b0b3a1b4ddf4e124872da6c2f632bfed957e9 +[0x492ce020fe2534a5789dc3848806c78f4f6711397f08e7e7a12ca5a4483c8aa6 ]) AT_CLEANUP diff --git a/tests/hmac02.at b/tests/hmac02.at index 2b3126b..d525637 100644 --- a/tests/hmac02.at +++ b/tests/hmac02.at @@ -19,7 +19,7 @@ AT_KEYWORDS([hmac hmac02]) AT_CHECK([thmac Jefe "what do ya want for nothing?"], [0], -[0xeffcdf6ae5eb2fa2d27416d5f184df9c259a7c79 +[0x5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843 ]) AT_CLEANUP diff --git a/tests/hmac03.at b/tests/hmac03.at index 85f6330..9316b15 100644 --- a/tests/hmac03.at +++ b/tests/hmac03.at @@ -20,7 +20,7 @@ AT_KEYWORDS([hmac hmac03]) AT_CHECK([thmac "0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" \ "0xDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD"], [0], -[0xd730594d167e35d5956fd8003d0db3d3f46dc7bb +[0x7dda3cc169743a6484649f94f0eda0f9f2ff496a9733fb796ed5adb40a44c3c1 ]) AT_CLEANUP diff --git a/tests/thmac.c b/tests/thmac.c index 956bc02..5c957dc 100644 --- a/tests/thmac.c +++ b/tests/thmac.c @@ -20,6 +20,7 @@ #include #include #include "libeclat.h" +#include "sha256.h" char *progname; @@ -106,7 +107,7 @@ main(int argc, char **argv) size_t keylen; void *text; size_t textlen; - unsigned char digest[20]; + unsigned char digest[SHA256_DIGEST_SIZE]; progname = argv[0]; if (argc != 3) { @@ -120,7 +121,7 @@ main(int argc, char **argv) rc = xdecode(argv[2], &text, &textlen); xdecode_assert(rc, argv[2], "text"); - hmac_sha1(text, textlen, key, keylen, digest); + hmac_sha256(text, textlen, key, keylen, digest); xdump(digest, sizeof(digest)); return 0; -- cgit v1.2.1