diff --git a/include/cryb/Makefile.am b/include/cryb/Makefile.am index 448365e..62ac784 100644 --- a/include/cryb/Makefile.am +++ b/include/cryb/Makefile.am @@ -10,6 +10,8 @@ cryb_HEADERS = \ hmac.h \ hotp.h \ mac.h \ + md2.h \ + md4.h \ md5.h \ oath.h \ oath_constants.h \ @@ -18,6 +20,9 @@ cryb_HEADERS = \ rfc3986.h \ rfc4648.h \ sha1.h \ + sha256.h \ + sha384.h \ + sha512.h \ to.h \ totp.h \ version.h diff --git a/include/cryb/md2.h b/include/cryb/md2.h new file mode 100644 index 0000000..3cd5c59 --- /dev/null +++ b/include/cryb/md2.h @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2006-2007 Christophe Devine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Cryb$ + */ + +#ifndef CRYB_MD2_H_INCLUDED +#define CRYB_MD2_H_INCLUDED + +#define MD2_DIGEST_LEN 16 + +#define md2_digest cryb_md2_digest +#define md2_ctx cryb_md2_ctx +#define md2_init cryb_md2_init +#define md2_update cryb_md2_update +#define md2_final cryb_md2_final +#define md2_complete cryb_md2_complete + +extern struct digest_algorithm md2_digest; + +/** + * \brief MD2 context structure + */ +typedef struct +{ + unsigned char cksum[16]; /*!< checksum of the data block */ + unsigned char state[48]; /*!< intermediate digest state */ + unsigned char buffer[16]; /*!< data block being processed */ + + unsigned char ipad[64]; /*!< HMAC: inner padding */ + unsigned char opad[64]; /*!< HMAC: outer padding */ + int left; /*!< amount of data in buffer */ +} +md2_ctx; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief MD2 context setup + * + * \param ctx context to be initialized + */ +void md2_init( md2_ctx *ctx ); + +/** + * \brief MD2 process buffer + * + * \param ctx MD2 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void md2_update( md2_ctx *ctx, const void *input, int ilen ); + +/** + * \brief MD2 final digest + * + * \param ctx MD2 context + * \param output MD2 checksum result + */ +void md2_final( md2_ctx *ctx, unsigned char output[16] ); + +/** + * \brief Output = MD2( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output MD2 checksum result + */ +void md2_complete( const void *input, int ilen, unsigned char output[16] ); + +/** + * \brief MD2 HMAC context setup + * + * \param ctx HMAC context to be initialized + * \param key HMAC secret key + * \param keylen length of the HMAC key + */ +void md2_hmac_init( md2_ctx *ctx, unsigned char *key, int keylen ); + +/** + * \brief MD2 HMAC process buffer + * + * \param ctx HMAC context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void md2_hmac_update( md2_ctx *ctx, unsigned char *input, int ilen ); + +/** + * \brief MD2 HMAC final digest + * + * \param ctx HMAC context + * \param output MD2 HMAC checksum result + */ +void md2_hmac_final( md2_ctx *ctx, unsigned char output[16] ); + +/** + * \brief Output = HMAC-MD2( hmac key, input buffer ) + * + * \param key HMAC secret key + * \param keylen length of the HMAC key + * \param input buffer holding the data + * \param ilen length of the input data + * \param output HMAC-MD2 result + */ +void md2_hmac_complete( unsigned char *key, int keylen, + unsigned char *input, int ilen, + unsigned char output[16] ); + +#ifdef __cplusplus +} +#endif + +#endif /* md2.h */ diff --git a/include/cryb/md4.h b/include/cryb/md4.h new file mode 100644 index 0000000..624c088 --- /dev/null +++ b/include/cryb/md4.h @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2006-2007 Christophe Devine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Cryb$ + */ + +#ifndef CRYB_MD4_H_INCLUDED +#define CRYB_MD4_H_INCLUDED + +#define MD4_DIGEST_LEN 16 + +#define md4_digest cryb_md4_digest +#define md4_ctx cryb_md4_ctx +#define md4_init cryb_md4_init +#define md4_update cryb_md4_update +#define md4_final cryb_md4_final +#define md4_complete cryb_md4_complete + +extern struct digest_algorithm md4_digest; + +/** + * \brief MD4 context structure + */ +typedef struct +{ + unsigned long total[2]; /*!< number of bytes processed */ + unsigned long state[4]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ + + unsigned char ipad[64]; /*!< HMAC: inner padding */ + unsigned char opad[64]; /*!< HMAC: outer padding */ +} +md4_ctx; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief MD4 context setup + * + * \param ctx context to be initialized + */ +void md4_init( md4_ctx *ctx ); + +/** + * \brief MD4 process buffer + * + * \param ctx MD4 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void md4_update( md4_ctx *ctx, const void *input, int ilen ); + +/** + * \brief MD4 final digest + * + * \param ctx MD4 context + * \param output MD4 checksum result + */ +void md4_final( md4_ctx *ctx, unsigned char output[16] ); + +/** + * \brief Output = MD4( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output MD4 checksum result + */ +void md4_complete( const void *input, int ilen, unsigned char output[16] ); + +/** + * \brief MD4 HMAC context setup + * + * \param ctx HMAC context to be initialized + * \param key HMAC secret key + * \param keylen length of the HMAC key + */ +void md4_hmac_init( md4_ctx *ctx, unsigned char *key, int keylen ); + +/** + * \brief MD4 HMAC process buffer + * + * \param ctx HMAC context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void md4_hmac_update( md4_ctx *ctx, unsigned char *input, int ilen ); + +/** + * \brief MD4 HMAC final digest + * + * \param ctx HMAC context + * \param output MD4 HMAC checksum result + */ +void md4_hmac_final( md4_ctx *ctx, unsigned char output[16] ); + +/** + * \brief Output = HMAC-MD4( hmac key, input buffer ) + * + * \param key HMAC secret key + * \param keylen length of the HMAC key + * \param input buffer holding the data + * \param ilen length of the input data + * \param output HMAC-MD4 result + */ +void md4_hmac_complete( unsigned char *key, int keylen, + unsigned char *input, int ilen, + unsigned char output[16] ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/cryb/md5.h b/include/cryb/md5.h index 7f9ec92..685249a 100644 --- a/include/cryb/md5.h +++ b/include/cryb/md5.h @@ -38,14 +38,14 @@ #define MD5_DIGEST_LEN 16 -#define md5_algorithm cryb_md5_algorithm +#define md5_digest cryb_md5_digest #define md5_ctx cryb_md5_ctx #define md5_init cryb_md5_init #define md5_update cryb_md5_update #define md5_final cryb_md5_final #define md5_complete cryb_md5_complete -extern struct digest_algorithm md5_algorithm; +extern struct digest_algorithm md5_digest; typedef struct md5_ctx { uint8_t block[64]; diff --git a/include/cryb/sha1.h b/include/cryb/sha1.h index 8e76c69..8eec2d8 100644 --- a/include/cryb/sha1.h +++ b/include/cryb/sha1.h @@ -38,14 +38,14 @@ #define SHA1_DIGEST_LEN 20 -#define sha1_algorithm cryb_sha1_algorithm +#define sha1_digest cryb_sha1_digest #define sha1_ctx cryb_sha1_ctx #define sha1_init cryb_sha1_init #define sha1_update cryb_sha1_update #define sha1_final cryb_sha1_final #define sha1_complete cryb_sha1_complete -extern struct digest_algorithm sha1_algorithm; +extern struct digest_algorithm sha1_digest; typedef struct sha1_ctx { uint8_t block[64]; diff --git a/include/cryb/sha256.h b/include/cryb/sha256.h new file mode 100644 index 0000000..c44f706 --- /dev/null +++ b/include/cryb/sha256.h @@ -0,0 +1,126 @@ +/*- + * Copyright (c) 2005-2013 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Cryb$ + */ + +#ifndef CRYB_SHA256_H_INCLUDED +#define CRYB_SHA256_H_INCLUDED + +#define SHA256_DIGEST_LEN 32 + +/* + * Use #defines in order to avoid namespace collisions with anyone else's + * SHA256 code (e.g., the code in OpenSSL). + */ +#define sha256_digest cryb_sha256_digest +#define sha256_ctx cryb_sha256_ctx +#define sha256_init cryb_sha256_init +#define sha256_update cryb_sha256_update +#define sha256_final cryb_sha256_final +#define sha256_complete cryb_sha256_complete + +extern struct digest_algorithm sha256_digest; + +#define hmac_sha256_init cryb_hmac_sha256_init +#define hmac_sha256_update cryb_hmac_sha256_update +#define hmac_sha256_final cryb_hmac_sha256_final +#define hmac_sha256_complete cryb_hmac_sha256_complete +#define hmac_sha256_ctx cryb_hmac_sha256_ctx + +/* Context structure for SHA256 operations. */ +typedef struct { + uint32_t state[8]; + uint64_t count; + uint8_t buf[64]; +} sha256_ctx; + +/** + * sha256_init(ctx): + * Initialize the SHA256 context ${ctx}. + */ +void sha256_init(sha256_ctx *); + +/** + * sha256_update(ctx, in, len): + * Input ${len} bytes from ${in} into the SHA256 context ${ctx}. + */ +void sha256_update(sha256_ctx *, const void *, size_t); + +/** + * sha256_final(ctx, digest): + * Output the SHA256 hash of the data input to the context ${ctx} into the + * buffer ${digest}. + */ +void sha256_final(sha256_ctx *, uint8_t[SHA256_DIGEST_LEN]); + +/** + * sha256_complete(in, len, digest): + * Compute the SHA256 hash of ${len} bytes from $in} and write it to ${digest}. + */ +void sha256_complete(const void *, size_t, uint8_t[SHA256_DIGEST_LEN]); + +/* Context structure for HMAC-SHA256 operations. */ +typedef struct { + sha256_ctx ictx; + sha256_ctx octx; +} hmac_sha256_ctx; + +/** + * hmac_sha256_init(ctx, K, Klen): + * Initialize the HMAC-SHA256 context ${ctx} with ${Klen} bytes of key from + * ${K}. + */ +void hmac_sha256_init(hmac_sha256_ctx *, const void *, size_t); + +/** + * hmac_sha256_update(ctx, in, len): + * Input ${len} bytes from ${in} into the HMAC-SHA256 context ${ctx}. + */ +void hmac_sha256_update(hmac_sha256_ctx *, const void *, size_t); + +/** + * hmac_sha256_final(ctx, digest): + * Output the HMAC-SHA256 of the data input to the context ${ctx} into the + * buffer ${digest}. + */ +void hmac_sha256_final(hmac_sha256_ctx *, uint8_t[SHA256_DIGEST_LEN]); + +/** + * hmac_sha256_complete(K, Klen, in, len, digest): + * Compute the HMAC-SHA256 of ${len} bytes from ${in} using the key ${K} of + * length ${Klen}, and write the result to ${digest}. + */ +void hmac_sha256_complete(const void *, size_t, const void *, size_t, uint8_t[32]); + +/** + * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): + * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and + * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). + */ +void pbkdf2_sha256(const uint8_t *, size_t, const uint8_t *, size_t, + uint64_t, uint8_t *, size_t); + +#endif diff --git a/include/cryb/sha384.h b/include/cryb/sha384.h new file mode 100644 index 0000000..f16da76 --- /dev/null +++ b/include/cryb/sha384.h @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2006-2007 Christophe Devine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Cryb$ + */ + +#ifndef CRYB_SHA384_H_INCLUDED +#define CRYB_SHA384_H_INCLUDED + +#define SHA384_DIGEST_LEN 48 + +#define sha384_digest cryb_sha384_digest +#define sha384_ctx cryb_sha384_ctx +#define sha384_init cryb_sha384_init +#define sha384_update cryb_sha384_update +#define sha384_final cryb_sha384_final +#define sha384_complete cryb_sha384_complete + +extern struct digest_algorithm sha384_digest; + +/** + * \brief SHA-384 context structure + */ +typedef struct +{ + uint64_t total[2]; /*!< number of bytes processed */ + uint64_t state[8]; /*!< intermediate digest state */ + uint8_t buffer[128]; /*!< data block being processed */ + + uint8_t ipad[128]; /*!< HMAC: inner padding */ + uint8_t opad[128]; /*!< HMAC: outer padding */ +} +sha384_ctx; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief SHA-384 context setup + * + * \param ctx context to be initialized + */ +void sha384_init( sha384_ctx *ctx ); + +/** + * \brief SHA-384 process buffer + * + * \param ctx SHA-384 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void sha384_update( sha384_ctx *ctx, const void *input, int ilen ); + +/** + * \brief SHA-384 final digest + * + * \param ctx SHA-384 context + * \param output SHA-384/384 checksum result + */ +void sha384_final( sha384_ctx *ctx, unsigned char output[64] ); + +/** + * \brief Output = SHA-384( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output SHA-384/384 checksum result + */ +void sha384_complete( const void *input, int ilen, + unsigned char output[64] ); + +/** + * \brief SHA-384 HMAC context setup + * + * \param ctx HMAC context to be initialized + * \param key HMAC secret key + * \param keylen length of the HMAC key + */ +void sha384_hmac_init( sha384_ctx *ctx, unsigned char *key, int keylen ); + +/** + * \brief SHA-384 HMAC process buffer + * + * \param ctx HMAC context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void sha384_hmac_update( sha384_ctx *ctx, unsigned char *input, int ilen ); + +/** + * \brief SHA-384 HMAC final digest + * + * \param ctx HMAC context + * \param output SHA-384/384 HMAC checksum result + */ +void sha384_hmac_final( sha384_ctx *ctx, unsigned char output[64] ); + +/** + * \brief Output = HMAC-SHA-384( hmac key, input buffer ) + * + * \param key HMAC secret key + * \param keylen length of the HMAC key + * \param input buffer holding the data + * \param ilen length of the input data + * \param output HMAC-SHA-384/384 result + */ +void sha384_hmac_complete( unsigned char *key, int keylen, + unsigned char *input, int ilen, + unsigned char output[64] ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/cryb/sha512.h b/include/cryb/sha512.h new file mode 100644 index 0000000..373fdcf --- /dev/null +++ b/include/cryb/sha512.h @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2006-2007 Christophe Devine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Cryb$ + */ + +#ifndef CRYB_SHA512_H_INCLUDED +#define CRYB_SHA512_H_INCLUDED + +#define SHA512_DIGEST_LEN 64 + +#define sha512_digest cryb_sha512_digest +#define sha512_ctx cryb_sha512_ctx +#define sha512_init cryb_sha512_init +#define sha512_update cryb_sha512_update +#define sha512_final cryb_sha512_final +#define sha512_complete cryb_sha512_complete + +extern struct digest_algorithm sha512_digest; + +/** + * \brief SHA-512 context structure + */ +typedef struct +{ + uint64_t total[2]; /*!< number of bytes processed */ + uint64_t state[8]; /*!< intermediate digest state */ + uint8_t buffer[128]; /*!< data block being processed */ + + uint8_t ipad[128]; /*!< HMAC: inner padding */ + uint8_t opad[128]; /*!< HMAC: outer padding */ +} +sha512_ctx; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief SHA-512 context setup + * + * \param ctx context to be initialized + */ +void sha512_init( sha512_ctx *ctx ); + +/** + * \brief SHA-512 process buffer + * + * \param ctx SHA-512 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void sha512_update( sha512_ctx *ctx, const void *input, int ilen ); + +/** + * \brief SHA-512 final digest + * + * \param ctx SHA-512 context + * \param output SHA-384/512 checksum result + */ +void sha512_final( sha512_ctx *ctx, unsigned char output[64] ); + +/** + * \brief Output = SHA-512( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output SHA-384/512 checksum result + */ +void sha512_complete( const void *input, int ilen, + unsigned char output[64] ); + +/** + * \brief SHA-512 HMAC context setup + * + * \param ctx HMAC context to be initialized + * \param key HMAC secret key + * \param keylen length of the HMAC key + */ +void sha512_hmac_init( sha512_ctx *ctx, unsigned char *key, int keylen ); + +/** + * \brief SHA-512 HMAC process buffer + * + * \param ctx HMAC context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void sha512_hmac_update( sha512_ctx *ctx, unsigned char *input, int ilen ); + +/** + * \brief SHA-512 HMAC final digest + * + * \param ctx HMAC context + * \param output SHA-384/512 HMAC checksum result + */ +void sha512_hmac_final( sha512_ctx *ctx, unsigned char output[64] ); + +/** + * \brief Output = HMAC-SHA-512( hmac key, input buffer ) + * + * \param key HMAC secret key + * \param keylen length of the HMAC key + * \param input buffer holding the data + * \param ilen length of the input data + * \param output HMAC-SHA-384/512 result + */ +void sha512_hmac_complete( unsigned char *key, int keylen, + unsigned char *input, int ilen, + unsigned char output[64] ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/digest/Makefile.am b/lib/digest/Makefile.am index 4afaa36..401f1b3 100644 --- a/lib/digest/Makefile.am +++ b/lib/digest/Makefile.am @@ -5,5 +5,10 @@ AM_CPPFLAGS = -I$(top_srcdir)/include lib_LTLIBRARIES = libcryb-digest.la libcryb_digest_la_SOURCES = \ + md2.c \ + md4.c \ md5.c \ - sha1.c + sha1.c \ + sha256.c \ + sha384.c \ + sha512.c diff --git a/lib/digest/md2.c b/lib/digest/md2.c new file mode 100644 index 0000000..bac2f9e --- /dev/null +++ b/lib/digest/md2.c @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2006-2007 Christophe Devine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Cryb$ + */ +/* + * The MD2 algorithm was designed by Ron Rivest in 1989. + * + * http://www.ietf.org/rfc/rfc1115.txt + * http://www.ietf.org/rfc/rfc1319.txt + */ + +#include "cryb/impl.h" + +#include + +#include +#include + +static const unsigned char PI_SUBST[256] = +{ + 0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36, + 0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13, 0x62, 0xA7, 0x05, 0xF3, + 0xC0, 0xC7, 0x73, 0x8C, 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C, + 0x82, 0xCA, 0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16, + 0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12, 0xBE, 0x4E, + 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, 0xA0, 0xFB, 0xF5, 0x8E, + 0xBB, 0x2F, 0xEE, 0x7A, 0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2, + 0x07, 0x3F, 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21, + 0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, 0x35, 0x3E, + 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03, 0xFF, 0x19, 0x30, 0xB3, + 0x48, 0xA5, 0xB5, 0xD1, 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56, + 0xAA, 0xC6, 0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6, + 0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1, 0x45, 0x9D, + 0x70, 0x59, 0x64, 0x71, 0x87, 0x20, 0x86, 0x5B, 0xCF, 0x65, + 0xE6, 0x2D, 0xA8, 0x02, 0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0, + 0xB9, 0xF6, 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F, + 0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, 0xC3, 0x5C, + 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26, 0x2C, 0x53, 0x0D, 0x6E, + 0x85, 0x28, 0x84, 0x09, 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81, + 0x4D, 0x52, 0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA, + 0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A, 0x78, 0x88, + 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, 0xE9, 0xCB, 0xD5, 0xFE, + 0x3B, 0x00, 0x1D, 0x39, 0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58, + 0xD0, 0xE4, 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A, + 0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 0xDB, 0x99, + 0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14 +}; + +/* + * MD2 context setup + */ +void md2_init( md2_ctx *ctx ) +{ + memset( ctx, 0, sizeof( md2_ctx ) ); +} + +static void md2_process( md2_ctx *ctx ) +{ + int i, j; + unsigned char t = 0; + + for( i = 0; i < 16; i++ ) + { + ctx->state[i + 16] = ctx->buffer[i]; + ctx->state[i + 32] = + (unsigned char)( ctx->buffer[i] ^ ctx->state[i]); + } + + for( i = 0; i < 18; i++ ) + { + for( j = 0; j < 48; j++ ) + { + ctx->state[j] = (unsigned char) + ( ctx->state[j] ^ PI_SUBST[t] ); + t = ctx->state[j]; + } + + t = (unsigned char)( t + i ); + } + + t = ctx->cksum[15]; + + for( i = 0; i < 16; i++ ) + { + ctx->cksum[i] = (unsigned char) + ( ctx->cksum[i] ^ PI_SUBST[ctx->buffer[i] ^ t] ); + t = ctx->cksum[i]; + } +} + +/* + * MD2 process buffer + */ +void md2_update( md2_ctx *ctx, const void *input, int ilen ) +{ + int fill; + + while( ilen > 0 ) + { + if( ctx->left + ilen > 16 ) + fill = 16 - ctx->left; + else + fill = ilen; + + memcpy( ctx->buffer + ctx->left, input, fill ); + + ctx->left += fill; + input += fill; + ilen -= fill; + + if( ctx->left == 16 ) + { + ctx->left = 0; + md2_process( ctx ); + } + } +} + +/* + * MD2 final digest + */ +void md2_final( md2_ctx *ctx, unsigned char *output ) +{ + int i; + unsigned char x; + + x = (unsigned char)( 16 - ctx->left ); + + for( i = ctx->left; i < 16; i++ ) + ctx->buffer[i] = x; + + md2_process( ctx ); + + memcpy( ctx->buffer, ctx->cksum, sizeof ctx->cksum ); + md2_process( ctx ); + + memcpy( output, ctx->state, MD2_DIGEST_LEN ); +} + +/* + * output = MD2( input buffer ) + */ +void md2_complete( const void *input, int ilen, unsigned char *output ) +{ + md2_ctx ctx; + + md2_init( &ctx ); + md2_update( &ctx, input, ilen ); + md2_final( &ctx, output ); + + memset( &ctx, 0, sizeof( md2_ctx ) ); +} + +/* + * MD2 HMAC context setup + */ +void md2_hmac_init( md2_ctx *ctx, unsigned char *key, int keylen ) +{ + int i; + unsigned char sum[MD2_DIGEST_LEN]; + + if( keylen > 64 ) + { + md2_complete( key, keylen, sum ); + keylen = sizeof sum; + key = sum; + } + + memset( ctx->ipad, 0x36, sizeof ctx->ipad ); + memset( ctx->opad, 0x5C, sizeof ctx->opad ); + + for( i = 0; i < keylen; i++ ) + { + ctx->ipad[i] = (unsigned char)( ctx->ipad[i] ^ key[i] ); + ctx->opad[i] = (unsigned char)( ctx->opad[i] ^ key[i] ); + } + + md2_init( ctx ); + md2_update( ctx, ctx->ipad, sizeof ctx->ipad ); + + memset( sum, 0, sizeof( sum ) ); +} + +/* + * MD2 HMAC process buffer + */ +void md2_hmac_update( md2_ctx *ctx, unsigned char *input, int ilen ) +{ + md2_update( ctx, input, ilen ); +} + +/* + * MD2 HMAC final digest + */ +void md2_hmac_final( md2_ctx *ctx, unsigned char *output ) +{ + unsigned char tmpbuf[MD2_DIGEST_LEN]; + + md2_final( ctx, tmpbuf ); + md2_init( ctx ); + md2_update( ctx, ctx->opad, sizeof ctx->opad ); + md2_update( ctx, tmpbuf, sizeof tmpbuf ); + md2_final( ctx, output ); + + memset( tmpbuf, 0, sizeof( tmpbuf ) ); +} + +/* + * output = HMAC-MD2( hmac key, input buffer ) + */ +void md2_hmac_complete( unsigned char *key, int keylen, unsigned char *input, int ilen, + unsigned char *output ) +{ + md2_ctx ctx; + + md2_hmac_init( &ctx, key, keylen ); + md2_hmac_update( &ctx, input, ilen ); + md2_hmac_final( &ctx, output ); + + memset( &ctx, 0, sizeof( md2_ctx ) ); +} + +struct digest_algorithm md2_digest = { + .name = "md2", + .contextlen = sizeof md2_digest, + .digestlen = MD2_DIGEST_LEN, + .init = (digest_init_func)md2_init, + .update = (digest_update_func)md2_update, + .final = (digest_final_func)md2_final, + .complete = (digest_complete_func)md2_complete, +}; diff --git a/lib/digest/md4.c b/lib/digest/md4.c new file mode 100644 index 0000000..a81c44e --- /dev/null +++ b/lib/digest/md4.c @@ -0,0 +1,356 @@ +/* + * Copyright (c) 2006-2007 Christophe Devine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Cryb$ + */ +/* + * The MD4 algorithm was designed by Ron Rivest in 1990. + * + * http://www.ietf.org/rfc/rfc1186.txt + * http://www.ietf.org/rfc/rfc1320.txt + */ + +#include "cryb/impl.h" + +#include + +#include +#include + +/* + * 32-bit integer manipulation macros (little endian) + */ +#ifndef GET_ULONG_LE +#define GET_ULONG_LE(n,b,i) \ +do { \ + (n) = ( (unsigned long) (b)[(i) ] ) \ + | ( (unsigned long) (b)[(i) + 1] << 8 ) \ + | ( (unsigned long) (b)[(i) + 2] << 16 ) \ + | ( (unsigned long) (b)[(i) + 3] << 24 ); \ +} while (0) +#endif + +#ifndef PUT_ULONG_LE +#define PUT_ULONG_LE(n,b,i) \ +do { \ + (b)[(i) ] = (unsigned char) ( (n) ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \ +} while (0) +#endif + +/* + * MD4 context setup + */ +void md4_init( md4_ctx *ctx ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; +} + +static void md4_process( md4_ctx *ctx, const unsigned char *data ) +{ + unsigned long X[16], A, B, C, D; + + GET_ULONG_LE( X[ 0], data, 0 ); + GET_ULONG_LE( X[ 1], data, 4 ); + GET_ULONG_LE( X[ 2], data, 8 ); + GET_ULONG_LE( X[ 3], data, 12 ); + GET_ULONG_LE( X[ 4], data, 16 ); + GET_ULONG_LE( X[ 5], data, 20 ); + GET_ULONG_LE( X[ 6], data, 24 ); + GET_ULONG_LE( X[ 7], data, 28 ); + GET_ULONG_LE( X[ 8], data, 32 ); + GET_ULONG_LE( X[ 9], data, 36 ); + GET_ULONG_LE( X[10], data, 40 ); + GET_ULONG_LE( X[11], data, 44 ); + GET_ULONG_LE( X[12], data, 48 ); + GET_ULONG_LE( X[13], data, 52 ); + GET_ULONG_LE( X[14], data, 56 ); + GET_ULONG_LE( X[15], data, 60 ); + +#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + +#define F(x, y, z) ((x & y) | ((~x) & z)) +#define P(a,b,c,d,x,s) { a += F(b,c,d) + x; a = S(a,s); } + + P( A, B, C, D, X[ 0], 3 ); + P( D, A, B, C, X[ 1], 7 ); + P( C, D, A, B, X[ 2], 11 ); + P( B, C, D, A, X[ 3], 19 ); + P( A, B, C, D, X[ 4], 3 ); + P( D, A, B, C, X[ 5], 7 ); + P( C, D, A, B, X[ 6], 11 ); + P( B, C, D, A, X[ 7], 19 ); + P( A, B, C, D, X[ 8], 3 ); + P( D, A, B, C, X[ 9], 7 ); + P( C, D, A, B, X[10], 11 ); + P( B, C, D, A, X[11], 19 ); + P( A, B, C, D, X[12], 3 ); + P( D, A, B, C, X[13], 7 ); + P( C, D, A, B, X[14], 11 ); + P( B, C, D, A, X[15], 19 ); + +#undef P +#undef F + +#define F(x,y,z) ((x & y) | (x & z) | (y & z)) +#define P(a,b,c,d,x,s) { a += F(b,c,d) + x + 0x5A827999; a = S(a,s); } + + P( A, B, C, D, X[ 0], 3 ); + P( D, A, B, C, X[ 4], 5 ); + P( C, D, A, B, X[ 8], 9 ); + P( B, C, D, A, X[12], 13 ); + P( A, B, C, D, X[ 1], 3 ); + P( D, A, B, C, X[ 5], 5 ); + P( C, D, A, B, X[ 9], 9 ); + P( B, C, D, A, X[13], 13 ); + P( A, B, C, D, X[ 2], 3 ); + P( D, A, B, C, X[ 6], 5 ); + P( C, D, A, B, X[10], 9 ); + P( B, C, D, A, X[14], 13 ); + P( A, B, C, D, X[ 3], 3 ); + P( D, A, B, C, X[ 7], 5 ); + P( C, D, A, B, X[11], 9 ); + P( B, C, D, A, X[15], 13 ); + +#undef P +#undef F + +#define F(x,y,z) (x ^ y ^ z) +#define P(a,b,c,d,x,s) { a += F(b,c,d) + x + 0x6ED9EBA1; a = S(a,s); } + + P( A, B, C, D, X[ 0], 3 ); + P( D, A, B, C, X[ 8], 9 ); + P( C, D, A, B, X[ 4], 11 ); + P( B, C, D, A, X[12], 15 ); + P( A, B, C, D, X[ 2], 3 ); + P( D, A, B, C, X[10], 9 ); + P( C, D, A, B, X[ 6], 11 ); + P( B, C, D, A, X[14], 15 ); + P( A, B, C, D, X[ 1], 3 ); + P( D, A, B, C, X[ 9], 9 ); + P( C, D, A, B, X[ 5], 11 ); + P( B, C, D, A, X[13], 15 ); + P( A, B, C, D, X[ 3], 3 ); + P( D, A, B, C, X[11], 9 ); + P( C, D, A, B, X[ 7], 11 ); + P( B, C, D, A, X[15], 15 ); + +#undef F +#undef P + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; +} + +/* + * MD4 process buffer + */ +void md4_update( md4_ctx *ctx, const void *input, int ilen ) +{ + int fill; + unsigned long left; + + if( ilen <= 0 ) + return; + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (unsigned long) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), + (void *) input, fill ); + md4_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + md4_process( ctx, input ); + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + { + memcpy( (void *) (ctx->buffer + left), + (void *) input, ilen ); + } +} + +static const unsigned char md4_padding[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * MD4 final digest + */ +void md4_final( md4_ctx *ctx, unsigned char *output ) +{ + unsigned long last, padn; + unsigned long high, low; + unsigned char msglen[8]; + + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_ULONG_LE( low, msglen, 0 ); + PUT_ULONG_LE( high, msglen, 4 ); + + last = ctx->total[0] & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + md4_update( ctx, md4_padding, padn ); + md4_update( ctx, msglen, 8 ); + + PUT_ULONG_LE( ctx->state[0], output, 0 ); + PUT_ULONG_LE( ctx->state[1], output, 4 ); + PUT_ULONG_LE( ctx->state[2], output, 8 ); + PUT_ULONG_LE( ctx->state[3], output, 12 ); +} + +/* + * output = MD4( input buffer ) + */ +void md4_complete( const void *input, int ilen, unsigned char *output ) +{ + md4_ctx ctx; + + md4_init( &ctx ); + md4_update( &ctx, input, ilen ); + md4_final( &ctx, output ); + + memset( &ctx, 0, sizeof( md4_ctx ) ); +} + +/* + * MD4 HMAC context setup + */ +void md4_hmac_init( md4_ctx *ctx, unsigned char *key, int keylen ) +{ + int i; + unsigned char sum[16]; + + if( keylen > 64 ) + { + md4_complete( key, keylen, sum ); + keylen = 16; + key = sum; + } + + memset( ctx->ipad, 0x36, 64 ); + memset( ctx->opad, 0x5C, 64 ); + + for( i = 0; i < keylen; i++ ) + { + ctx->ipad[i] = (unsigned char)( ctx->ipad[i] ^ key[i] ); + ctx->opad[i] = (unsigned char)( ctx->opad[i] ^ key[i] ); + } + + md4_init( ctx ); + md4_update( ctx, ctx->ipad, 64 ); + + memset( sum, 0, sizeof( sum ) ); +} + +/* + * MD4 HMAC process buffer + */ +void md4_hmac_update( md4_ctx *ctx, unsigned char *input, int ilen ) +{ + md4_update( ctx, input, ilen ); +} + +/* + * MD4 HMAC final digest + */ +void md4_hmac_final( md4_ctx *ctx, unsigned char *output ) +{ + unsigned char tmpbuf[MD4_DIGEST_LEN]; + + md4_final( ctx, tmpbuf ); + md4_init( ctx ); + md4_update( ctx, ctx->opad, 64 ); + md4_update( ctx, tmpbuf, 16 ); + md4_final( ctx, output ); + + memset( tmpbuf, 0, sizeof( tmpbuf ) ); +} + +/* + * output = HMAC-MD4( hmac key, input buffer ) + */ +void md4_hmac_complete( unsigned char *key, int keylen, unsigned char *input, int ilen, + unsigned char output[16] ) +{ + md4_ctx ctx; + + md4_hmac_init( &ctx, key, keylen ); + md4_hmac_update( &ctx, input, ilen ); + md4_hmac_final( &ctx, output ); + + memset( &ctx, 0, sizeof( md4_ctx ) ); +} + +struct digest_algorithm md4_digest = { + .name = "md4", + .contextlen = sizeof md4_digest, + .digestlen = MD4_DIGEST_LEN, + .init = (digest_init_func)md4_init, + .update = (digest_update_func)md4_update, + .final = (digest_final_func)md4_final, + .complete = (digest_complete_func)md4_complete, +}; diff --git a/lib/digest/md5.c b/lib/digest/md5.c index 9ad93ea..94cf433 100644 --- a/lib/digest/md5.c +++ b/lib/digest/md5.c @@ -35,10 +35,6 @@ #include "cryb/impl.h" -#include -#include -#include - #ifdef HAVE_SYS_ENDIAN_H #include #endif @@ -48,6 +44,9 @@ #include #endif +#include +#include + #include #include #include @@ -209,19 +208,19 @@ md5_update(struct md5_ctx *ctx, const void *buf, size_t len) size_t copylen; while (len) { - if (ctx->blocklen > 0 || len < 64) { - copylen = 64 - ctx->blocklen; + if (ctx->blocklen > 0 || len < sizeof ctx->block) { + copylen = sizeof ctx->block - ctx->blocklen; if (copylen > len) copylen = len; memcpy(ctx->block + ctx->blocklen, buf, copylen); ctx->blocklen += copylen; - if (ctx->blocklen == 64) { + if (ctx->blocklen == sizeof ctx->block) { md5_compute(ctx, ctx->block); ctx->blocklen = 0; - memset(ctx->block, 0, 64); + memset(ctx->block, 0, sizeof ctx->block); } } else { - copylen = 64; + copylen = sizeof ctx->block; md5_compute(ctx, buf); } ctx->bitlen += copylen * 8; @@ -238,7 +237,7 @@ md5_final(struct md5_ctx *ctx, void *digest) if (ctx->blocklen > 56) { md5_compute(ctx, ctx->block); ctx->blocklen = 0; - memset(ctx->block, 0, 64); + memset(ctx->block, 0, sizeof ctx->block); } le32enc(ctx->block + 56, ctx->bitlen & 0xffffffffUL); le32enc(ctx->block + 60, ctx->bitlen >> 32); diff --git a/lib/digest/sha1.c b/lib/digest/sha1.c index c33a08a..219a5d0 100644 --- a/lib/digest/sha1.c +++ b/lib/digest/sha1.c @@ -35,10 +35,6 @@ #include "cryb/impl.h" -#include -#include -#include - #ifdef HAVE_SYS_ENDIAN_H #include #endif @@ -48,6 +44,9 @@ #include #endif +#include +#include + #include #include @@ -119,19 +118,19 @@ sha1_update(struct sha1_ctx *ctx, const void *buf, size_t len) size_t copylen; while (len) { - if (ctx->blocklen > 0 || len < 64) { + if (ctx->blocklen > 0 || len < sizeof ctx->block) { copylen = sizeof ctx->block - ctx->blocklen; if (copylen > len) copylen = len; memcpy(ctx->block + ctx->blocklen, buf, copylen); ctx->blocklen += copylen; - if (ctx->blocklen == 64) { + if (ctx->blocklen == sizeof ctx->block) { sha1_compute(ctx, ctx->block); ctx->blocklen = 0; - memset(ctx->block, 0, 64); + memset(ctx->block, 0, sizeof ctx->block); } } else { - copylen = 64; + copylen = sizeof ctx->block; sha1_compute(ctx, buf); } ctx->bitlen += copylen * 8; @@ -149,7 +148,7 @@ sha1_final(struct sha1_ctx *ctx, void *digest) if (ctx->blocklen > 56) { sha1_compute(ctx, ctx->block); ctx->blocklen = 0; - memset(ctx->block, 0, 64); + memset(ctx->block, 0, sizeof ctx->block); } hi = htobe32(ctx->bitlen >> 32); lo = htobe32(ctx->bitlen & 0xffffffffUL); diff --git a/lib/digest/sha256.c b/lib/digest/sha256.c new file mode 100644 index 0000000..a641da7 --- /dev/null +++ b/lib/digest/sha256.c @@ -0,0 +1,477 @@ +/*- + * Copyright (c) 2005-2013 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Cryb$ + */ + +#include "cryb/impl.h" + +#ifdef HAVE_SYS_ENDIAN_H +#include +#endif + +#ifdef HAVE_ENDIAN_H +#define _BSD_SOURCE +#include +#endif + +#include +#include + +#include +#include + +/* + * Encode a length len/4 vector of (uint32_t) into a length len vector of + * (uint8_t) in big-endian form. Assumes len is a multiple of 4. + */ +static void +be32enc_vect(uint8_t *dst, const uint32_t *src, size_t len) +{ + size_t i; + + for (i = 0; i < len / 4; i++) + be32enc(dst + i * 4, src[i]); +} + +/* + * Decode a big-endian length len vector of (uint8_t) into a length + * len/4 vector of (uint32_t). Assumes len is a multiple of 4. + */ +static void +be32dec_vect(uint32_t *dst, const uint8_t *src, size_t len) +{ + size_t i; + + for (i = 0; i < len / 4; i++) + dst[i] = be32dec(src + i * 4); +} + +/* Elementary functions used by SHA256 */ +#define Ch(x, y, z) ((x & (y ^ z)) ^ z) +#define Maj(x, y, z) ((x & (y | z)) | (y & z)) +#define SHR(x, n) (x >> n) +#define ROTR(x, n) ((x >> n) | (x << (32 - n))) +#define S0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) +#define S1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) +#define s0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3)) +#define s1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10)) + +/* SHA256 round function */ +#define RND(a, b, c, d, e, f, g, h, k) \ + t0 = h + S1(e) + Ch(e, f, g) + k; \ + t1 = S0(a) + Maj(a, b, c); \ + d += t0; \ + h = t0 + t1; + +/* Adjusted round function for rotating state */ +#define RNDr(S, W, i, k) \ + RND(S[(64 - i) % 8], S[(65 - i) % 8], \ + S[(66 - i) % 8], S[(67 - i) % 8], \ + S[(68 - i) % 8], S[(69 - i) % 8], \ + S[(70 - i) % 8], S[(71 - i) % 8], \ + W[i] + k) + +/* + * SHA256 block compression function. The 256-bit state is transformed via + * the 512-bit input block to produce a new state. + */ +static void +sha256_Transform(uint32_t * state, const uint8_t block[64]) +{ + uint32_t W[64]; + uint32_t S[8]; + uint32_t t0, t1; + int i; + + /* 1. Prepare message schedule W. */ + be32dec_vect(W, block, 64); + for (i = 16; i < 64; i++) + W[i] = s1(W[i - 2]) + W[i - 7] + s0(W[i - 15]) + W[i - 16]; + + /* 2. Initialize working variables. */ + memcpy(S, state, 32); + + /* 3. Mix. */ + RNDr(S, W, 0, 0x428a2f98); + RNDr(S, W, 1, 0x71374491); + RNDr(S, W, 2, 0xb5c0fbcf); + RNDr(S, W, 3, 0xe9b5dba5); + RNDr(S, W, 4, 0x3956c25b); + RNDr(S, W, 5, 0x59f111f1); + RNDr(S, W, 6, 0x923f82a4); + RNDr(S, W, 7, 0xab1c5ed5); + RNDr(S, W, 8, 0xd807aa98); + RNDr(S, W, 9, 0x12835b01); + RNDr(S, W, 10, 0x243185be); + RNDr(S, W, 11, 0x550c7dc3); + RNDr(S, W, 12, 0x72be5d74); + RNDr(S, W, 13, 0x80deb1fe); + RNDr(S, W, 14, 0x9bdc06a7); + RNDr(S, W, 15, 0xc19bf174); + RNDr(S, W, 16, 0xe49b69c1); + RNDr(S, W, 17, 0xefbe4786); + RNDr(S, W, 18, 0x0fc19dc6); + RNDr(S, W, 19, 0x240ca1cc); + RNDr(S, W, 20, 0x2de92c6f); + RNDr(S, W, 21, 0x4a7484aa); + RNDr(S, W, 22, 0x5cb0a9dc); + RNDr(S, W, 23, 0x76f988da); + RNDr(S, W, 24, 0x983e5152); + RNDr(S, W, 25, 0xa831c66d); + RNDr(S, W, 26, 0xb00327c8); + RNDr(S, W, 27, 0xbf597fc7); + RNDr(S, W, 28, 0xc6e00bf3); + RNDr(S, W, 29, 0xd5a79147); + RNDr(S, W, 30, 0x06ca6351); + RNDr(S, W, 31, 0x14292967); + RNDr(S, W, 32, 0x27b70a85); + RNDr(S, W, 33, 0x2e1b2138); + RNDr(S, W, 34, 0x4d2c6dfc); + RNDr(S, W, 35, 0x53380d13); + RNDr(S, W, 36, 0x650a7354); + RNDr(S, W, 37, 0x766a0abb); + RNDr(S, W, 38, 0x81c2c92e); + RNDr(S, W, 39, 0x92722c85); + RNDr(S, W, 40, 0xa2bfe8a1); + RNDr(S, W, 41, 0xa81a664b); + RNDr(S, W, 42, 0xc24b8b70); + RNDr(S, W, 43, 0xc76c51a3); + RNDr(S, W, 44, 0xd192e819); + RNDr(S, W, 45, 0xd6990624); + RNDr(S, W, 46, 0xf40e3585); + RNDr(S, W, 47, 0x106aa070); + RNDr(S, W, 48, 0x19a4c116); + RNDr(S, W, 49, 0x1e376c08); + RNDr(S, W, 50, 0x2748774c); + RNDr(S, W, 51, 0x34b0bcb5); + RNDr(S, W, 52, 0x391c0cb3); + RNDr(S, W, 53, 0x4ed8aa4a); + RNDr(S, W, 54, 0x5b9cca4f); + RNDr(S, W, 55, 0x682e6ff3); + RNDr(S, W, 56, 0x748f82ee); + RNDr(S, W, 57, 0x78a5636f); + RNDr(S, W, 58, 0x84c87814); + RNDr(S, W, 59, 0x8cc70208); + RNDr(S, W, 60, 0x90befffa); + RNDr(S, W, 61, 0xa4506ceb); + RNDr(S, W, 62, 0xbef9a3f7); + RNDr(S, W, 63, 0xc67178f2); + + /* 4. Mix local working variables into global state. */ + for (i = 0; i < 8; i++) + state[i] += S[i]; + + /* Clean the stack. */ + memset(W, 0, 256); + memset(S, 0, 32); + t0 = t1 = 0; +} + +static uint8_t PAD[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* Add padding and terminating bit-count. */ +static void +sha256_pad(sha256_ctx * ctx) +{ + uint8_t len[8]; + uint32_t r, plen; + + /* + * Convert length to a vector of bytes -- we do this now rather + * than later because the length will change after we pad. + */ + be64enc(len, ctx->count); + + /* Add 1--64 bytes so that the resulting length is 56 mod 64. */ + r = (ctx->count >> 3) & 0x3f; + plen = (r < 56) ? (56 - r) : (120 - r); + sha256_update(ctx, PAD, (size_t)plen); + + /* Add the terminating bit-count. */ + sha256_update(ctx, len, 8); +} + +/** + * sha256_init(ctx): + * Initialize the SHA256 context ${ctx}. + */ +void +sha256_init(sha256_ctx * ctx) +{ + + /* Zero bits processed so far. */ + ctx->count = 0; + + /* Magic initialization constants. */ + ctx->state[0] = 0x6A09E667; + ctx->state[1] = 0xBB67AE85; + ctx->state[2] = 0x3C6EF372; + ctx->state[3] = 0xA54FF53A; + ctx->state[4] = 0x510E527F; + ctx->state[5] = 0x9B05688C; + ctx->state[6] = 0x1F83D9AB; + ctx->state[7] = 0x5BE0CD19; +} + +/** + * sha256_update(ctx, in, len): + * Input ${len} bytes from ${in} into the SHA256 context ${ctx}. + */ +void +sha256_update(sha256_ctx * ctx, const void *in, size_t len) +{ + uint32_t r; + const uint8_t *src = in; + + /* Return immediately if we have nothing to do. */ + if (len == 0) + return; + + /* Number of bytes left in the buffer from previous updates. */ + r = (ctx->count >> 3) & 0x3f; + + /* Update number of bits. */ + ctx->count += (uint64_t)(len) << 3; + + /* Handle the case where we don't need to perform any transforms. */ + if (len < 64 - r) { + memcpy(&ctx->buf[r], src, len); + return; + } + + /* Finish the current block. */ + memcpy(&ctx->buf[r], src, 64 - r); + sha256_Transform(ctx->state, ctx->buf); + src += 64 - r; + len -= 64 - r; + + /* Perform complete blocks. */ + while (len >= 64) { + sha256_Transform(ctx->state, src); + src += 64; + len -= 64; + } + + /* Copy left over data into buffer. */ + memcpy(ctx->buf, src, len); +} + +/** + * sha256_final(ctx, digest): + * Output the SHA256 hash of the data input to the context ${ctx} into the + * buffer ${digest}. + */ +void +sha256_final(sha256_ctx * ctx, uint8_t digest[SHA256_DIGEST_LEN]) +{ + + /* Add padding. */ + sha256_pad(ctx); + + /* Write the hash. */ + be32enc_vect(digest, ctx->state, SHA256_DIGEST_LEN); + + /* Clear the context state. */ + memset((void *)ctx, 0, sizeof(*ctx)); +} + +/** + * sha256_complete(in, len, digest): + * Compute the SHA256 hash of ${len} bytes from $in} and write it to ${digest}. + */ +void +sha256_complete(const void * in, size_t len, uint8_t digest[SHA256_DIGEST_LEN]) +{ + sha256_ctx ctx; + + sha256_init(&ctx); + sha256_update(&ctx, in, len); + sha256_final(&ctx, digest); +} + +/** + * hmac_sha256_init(ctx, K, Klen): + * Initialize the HMAC-SHA256 context ${ctx} with ${Klen} bytes of key from + * ${K}. + */ +void +hmac_sha256_init(hmac_sha256_ctx * ctx, const void * _K, size_t Klen) +{ + uint8_t pad[64]; + uint8_t khash[SHA256_DIGEST_LEN]; + const uint8_t * K = _K; + size_t i; + + /* If Klen > 64, the key is really SHA256(K). */ + if (Klen > 64) { + sha256_init(&ctx->ictx); + sha256_update(&ctx->ictx, K, Klen); + sha256_final(&ctx->ictx, khash); + K = khash; + Klen = sizeof khash; + } + + /* Inner SHA256 operation is SHA256(K xor [block of 0x36] || data). */ + sha256_init(&ctx->ictx); + memset(pad, 0x36, 64); + for (i = 0; i < Klen; i++) + pad[i] ^= K[i]; + sha256_update(&ctx->ictx, pad, 64); + + /* Outer SHA256 operation is SHA256(K xor [block of 0x5c] || hash). */ + sha256_init(&ctx->octx); + memset(pad, 0x5c, 64); + for (i = 0; i < Klen; i++) + pad[i] ^= K[i]; + sha256_update(&ctx->octx, pad, 64); + + /* Clean the stack. */ + memset(khash, 0, sizeof khash); + memset(pad, 0, 64); +} + +/** + * hmac_sha256_update(ctx, in, len): + * Input ${len} bytes from ${in} into the HMAC-SHA256 context ${ctx}. + */ +void +hmac_sha256_update(hmac_sha256_ctx * ctx, const void *in, size_t len) +{ + + /* Feed data to the inner SHA256 operation. */ + sha256_update(&ctx->ictx, in, len); +} + +/** + * hmac_sha256_final(ctx, digest): + * Output the HMAC-SHA256 of the data input to the context ${ctx} into the + * buffer ${digest}. + */ +void +hmac_sha256_final(hmac_sha256_ctx * ctx, uint8_t digest[SHA256_DIGEST_LEN]) +{ + uint8_t ihash[SHA256_DIGEST_LEN]; + + /* Finish the inner SHA256 operation. */ + sha256_final(&ctx->ictx, ihash); + + /* Feed the inner hash to the outer SHA256 operation. */ + sha256_update(&ctx->octx, ihash, sizeof ihash); + + /* Finish the outer SHA256 operation. */ + sha256_final(&ctx->octx, digest); + + /* Clean the stack. */ + memset(ihash, 0, sizeof ihash); +} + +/** + * hmac_sha256_complete(K, Klen, in, len, digest): + * Compute the HMAC-SHA256 of ${len} bytes from ${in} using the key ${K} of + * length ${Klen}, and write the result to ${digest}. + */ +void +hmac_sha256_complete(const void * K, size_t Klen, const void * in, size_t len, + uint8_t digest[SHA256_DIGEST_LEN]) +{ + hmac_sha256_ctx ctx; + + hmac_sha256_init(&ctx, K, Klen); + hmac_sha256_update(&ctx, in, len); + hmac_sha256_final(&ctx, digest); +} + +/** + * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): + * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and + * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). + */ +void +pbkdf2_sha256(const uint8_t * passwd, size_t passwdlen, const uint8_t * salt, + size_t saltlen, uint64_t c, uint8_t * buf, size_t dkLen) +{ + hmac_sha256_ctx PShctx, hctx; + size_t i; + uint8_t ivec[4]; + uint8_t U[SHA256_DIGEST_LEN]; + uint8_t T[SHA256_DIGEST_LEN]; + uint64_t j; + unsigned int k; + size_t clen; + + /* Compute HMAC state after processing P and S. */ + hmac_sha256_init(&PShctx, passwd, passwdlen); + hmac_sha256_update(&PShctx, salt, saltlen); + + /* Iterate through the blocks. */ + for (i = 0; i * 32 < dkLen; i++) { + /* Generate INT(i + 1). */ + be32enc(ivec, (uint32_t)(i + 1)); + + /* Compute U_1 = PRF(P, S || INT(i)). */ + memcpy(&hctx, &PShctx, sizeof(hmac_sha256_ctx)); + hmac_sha256_update(&hctx, ivec, 4); + hmac_sha256_final(&hctx, U); + + /* T_i = U_1 ... */ + memcpy(T, U, sizeof T); + + for (j = 2; j <= c; j++) { + /* Compute U_j. */ + hmac_sha256_init(&hctx, passwd, passwdlen); + hmac_sha256_update(&hctx, U, 32); + hmac_sha256_final(&hctx, U); + + /* ... xor U_j ... */ + for (k = 0; k < sizeof T; k++) + T[k] ^= U[k]; + } + + /* Copy as many bytes as necessary into buf. */ + clen = dkLen - i * 32; + if (clen > 32) + clen = 32; + memcpy(&buf[i * 32], T, clen); + } + + /* Clean PShctx, since we never called _final on it. */ + memset(&PShctx, 0, sizeof(hmac_sha256_ctx)); +} + +struct digest_algorithm sha256_digest = { + .name = "sha256", + .contextlen = sizeof sha256_digest, + .digestlen = SHA256_DIGEST_LEN, + .init = (digest_init_func)sha256_init, + .update = (digest_update_func)sha256_update, + .final = (digest_final_func)sha256_final, + .complete = (digest_complete_func)sha256_complete, +}; diff --git a/lib/digest/sha384.c b/lib/digest/sha384.c new file mode 100644 index 0000000..00d336a --- /dev/null +++ b/lib/digest/sha384.c @@ -0,0 +1,419 @@ +/* + * Copyright (c) 2006-2007 Christophe Devine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Cryb$ + */ +/* + * The SHA-384 Secure Hash Standard was published by NIST in 2002. + * + * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf + */ + +#include "cryb/impl.h" + +#include +#include + +#include +#include + +static int is384 = 1; + +/* + * 64-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT64_BE +#define GET_UINT64_BE(n,b,i) \ +do { \ + (n) = ( (uint64_t) (b)[(i) ] << 56 ) \ + | ( (uint64_t) (b)[(i) + 1] << 48 ) \ + | ( (uint64_t) (b)[(i) + 2] << 40 ) \ + | ( (uint64_t) (b)[(i) + 3] << 32 ) \ + | ( (uint64_t) (b)[(i) + 4] << 24 ) \ + | ( (uint64_t) (b)[(i) + 5] << 16 ) \ + | ( (uint64_t) (b)[(i) + 6] << 8 ) \ + | ( (uint64_t) (b)[(i) + 7] ); \ +} while (0) +#endif + +#ifndef PUT_UINT64_BE +#define PUT_UINT64_BE(n,b,i) \ +do { \ + (b)[(i) ] = (unsigned char) ( (n) >> 56 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 48 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 40 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) >> 32 ); \ + (b)[(i) + 4] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 5] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 6] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 7] = (unsigned char) ( (n) ); \ +} while (0) +#endif + +/* XXX */ +#define UL64(x) x##ULL + +/* + * Round constants + */ +static const uint64_t K[80] = +{ + UL64(0x428A2F98D728AE22), UL64(0x7137449123EF65CD), + UL64(0xB5C0FBCFEC4D3B2F), UL64(0xE9B5DBA58189DBBC), + UL64(0x3956C25BF348B538), UL64(0x59F111F1B605D019), + UL64(0x923F82A4AF194F9B), UL64(0xAB1C5ED5DA6D8118), + UL64(0xD807AA98A3030242), UL64(0x12835B0145706FBE), + UL64(0x243185BE4EE4B28C), UL64(0x550C7DC3D5FFB4E2), + UL64(0x72BE5D74F27B896F), UL64(0x80DEB1FE3B1696B1), + UL64(0x9BDC06A725C71235), UL64(0xC19BF174CF692694), + UL64(0xE49B69C19EF14AD2), UL64(0xEFBE4786384F25E3), + UL64(0x0FC19DC68B8CD5B5), UL64(0x240CA1CC77AC9C65), + UL64(0x2DE92C6F592B0275), UL64(0x4A7484AA6EA6E483), + UL64(0x5CB0A9DCBD41FBD4), UL64(0x76F988DA831153B5), + UL64(0x983E5152EE66DFAB), UL64(0xA831C66D2DB43210), + UL64(0xB00327C898FB213F), UL64(0xBF597FC7BEEF0EE4), + UL64(0xC6E00BF33DA88FC2), UL64(0xD5A79147930AA725), + UL64(0x06CA6351E003826F), UL64(0x142929670A0E6E70), + UL64(0x27B70A8546D22FFC), UL64(0x2E1B21385C26C926), + UL64(0x4D2C6DFC5AC42AED), UL64(0x53380D139D95B3DF), + UL64(0x650A73548BAF63DE), UL64(0x766A0ABB3C77B2A8), + UL64(0x81C2C92E47EDAEE6), UL64(0x92722C851482353B), + UL64(0xA2BFE8A14CF10364), UL64(0xA81A664BBC423001), + UL64(0xC24B8B70D0F89791), UL64(0xC76C51A30654BE30), + UL64(0xD192E819D6EF5218), UL64(0xD69906245565A910), + UL64(0xF40E35855771202A), UL64(0x106AA07032BBD1B8), + UL64(0x19A4C116B8D2D0C8), UL64(0x1E376C085141AB53), + UL64(0x2748774CDF8EEB99), UL64(0x34B0BCB5E19B48A8), + UL64(0x391C0CB3C5C95A63), UL64(0x4ED8AA4AE3418ACB), + UL64(0x5B9CCA4F7763E373), UL64(0x682E6FF3D6B2B8A3), + UL64(0x748F82EE5DEFB2FC), UL64(0x78A5636F43172F60), + UL64(0x84C87814A1F0AB72), UL64(0x8CC702081A6439EC), + UL64(0x90BEFFFA23631E28), UL64(0xA4506CEBDE82BDE9), + UL64(0xBEF9A3F7B2C67915), UL64(0xC67178F2E372532B), + UL64(0xCA273ECEEA26619C), UL64(0xD186B8C721C0C207), + UL64(0xEADA7DD6CDE0EB1E), UL64(0xF57D4F7FEE6ED178), + UL64(0x06F067AA72176FBA), UL64(0x0A637DC5A2C898A6), + UL64(0x113F9804BEF90DAE), UL64(0x1B710B35131C471B), + UL64(0x28DB77F523047D84), UL64(0x32CAAB7B40C72493), + UL64(0x3C9EBE0A15C9BEBC), UL64(0x431D67C49C100D4C), + UL64(0x4CC5D4BECB3E42B6), UL64(0x597F299CFC657E2A), + UL64(0x5FCB6FAB3AD6FAEC), UL64(0x6C44198C4A475817) +}; + +/* + * SHA-384 context setup + */ +void sha384_init( sha384_ctx *ctx ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + if( is384 == 0 ) + { + /* SHA-384 */ + ctx->state[0] = UL64(0x6A09E667F3BCC908); + ctx->state[1] = UL64(0xBB67AE8584CAA73B); + ctx->state[2] = UL64(0x3C6EF372FE94F82B); + ctx->state[3] = UL64(0xA54FF53A5F1D36F1); + ctx->state[4] = UL64(0x510E527FADE682D1); + ctx->state[5] = UL64(0x9B05688C2B3E6C1F); + ctx->state[6] = UL64(0x1F83D9ABFB41BD6B); + ctx->state[7] = UL64(0x5BE0CD19137E2179); + } + else + { + /* SHA-384 */ + ctx->state[0] = UL64(0xCBBB9D5DC1059ED8); + ctx->state[1] = UL64(0x629A292A367CD507); + ctx->state[2] = UL64(0x9159015A3070DD17); + ctx->state[3] = UL64(0x152FECD8F70E5939); + ctx->state[4] = UL64(0x67332667FFC00B31); + ctx->state[5] = UL64(0x8EB44A8768581511); + ctx->state[6] = UL64(0xDB0C2E0D64F98FA7); + ctx->state[7] = UL64(0x47B5481DBEFA4FA4); + } +} + +static void sha384_process( sha384_ctx *ctx, const unsigned char *data ) +{ + int i; + uint64_t temp1, temp2, W[80]; + uint64_t A, B, C, D, E, F, G, H; + +#define SHR(x,n) (x >> n) +#define ROTR(x,n) (SHR(x,n) | (x << (64 - n))) + +#define S0(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHR(x, 7)) +#define S1(x) (ROTR(x,19) ^ ROTR(x,61) ^ SHR(x, 6)) + +#define S2(x) (ROTR(x,28) ^ ROTR(x,34) ^ ROTR(x,39)) +#define S3(x) (ROTR(x,14) ^ ROTR(x,18) ^ ROTR(x,41)) + +#define F0(x,y,z) ((x & y) | (z & (x | y))) +#define F1(x,y,z) (z ^ (x & (y ^ z))) + +#define P(a,b,c,d,e,f,g,h,x,K) \ +{ \ + temp1 = h + S3(e) + F1(e,f,g) + K + x; \ + temp2 = S2(a) + F0(a,b,c); \ + d += temp1; h = temp1 + temp2; \ +} + + for( i = 0; i < 16; i++ ) + { + GET_UINT64_BE( W[i], data, i << 3 ); + } + + for( ; i < 80; i++ ) + { + W[i] = S1(W[i - 2]) + W[i - 7] + + S0(W[i - 15]) + W[i - 16]; + } + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + E = ctx->state[4]; + F = ctx->state[5]; + G = ctx->state[6]; + H = ctx->state[7]; + i = 0; + + do + { + P( A, B, C, D, E, F, G, H, W[i], K[i] ); i++; + P( H, A, B, C, D, E, F, G, W[i], K[i] ); i++; + P( G, H, A, B, C, D, E, F, W[i], K[i] ); i++; + P( F, G, H, A, B, C, D, E, W[i], K[i] ); i++; + P( E, F, G, H, A, B, C, D, W[i], K[i] ); i++; + P( D, E, F, G, H, A, B, C, W[i], K[i] ); i++; + P( C, D, E, F, G, H, A, B, W[i], K[i] ); i++; + P( B, C, D, E, F, G, H, A, W[i], K[i] ); i++; + } + while( i < 80 ); + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; + ctx->state[4] += E; + ctx->state[5] += F; + ctx->state[6] += G; + ctx->state[7] += H; +} + +/* + * SHA-384 process buffer + */ +void sha384_update( sha384_ctx *ctx, const void *input, int ilen ) +{ + int fill; + uint64_t left; + + if( ilen <= 0 ) + return; + + left = ctx->total[0] & 0x7F; + fill = (int)( 128 - left ); + + ctx->total[0] += ilen; + + if( ctx->total[0] < (uint64_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), + (void *) input, fill ); + sha384_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 128 ) + { + sha384_process( ctx, input ); + input += 128; + ilen -= 128; + } + + if( ilen > 0 ) + { + memcpy( (void *) (ctx->buffer + left), + (void *) input, ilen ); + } +} + +static const unsigned char sha384_padding[128] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * SHA-384 final digest + */ +void sha384_final( sha384_ctx *ctx, unsigned char output[64] ) +{ + int last, padn; + uint64_t high, low; + unsigned char msglen[16]; + + high = ( ctx->total[0] >> 61 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT64_BE( high, msglen, 0 ); + PUT_UINT64_BE( low, msglen, 8 ); + + last = (int)( ctx->total[0] & 0x7F ); + padn = ( last < 112 ) ? ( 112 - last ) : ( 240 - last ); + + sha384_update( ctx, (unsigned char *) sha384_padding, padn ); + sha384_update( ctx, msglen, 16 ); + + PUT_UINT64_BE( ctx->state[0], output, 0 ); + PUT_UINT64_BE( ctx->state[1], output, 8 ); + PUT_UINT64_BE( ctx->state[2], output, 16 ); + PUT_UINT64_BE( ctx->state[3], output, 24 ); + PUT_UINT64_BE( ctx->state[4], output, 32 ); + PUT_UINT64_BE( ctx->state[5], output, 40 ); + + if( is384 == 0 ) + { + PUT_UINT64_BE( ctx->state[6], output, 48 ); + PUT_UINT64_BE( ctx->state[7], output, 56 ); + } +} + +/* + * output = SHA-384( input buffer ) + */ +void sha384_complete( const void *input, int ilen, + unsigned char output[64] ) +{ + sha384_ctx ctx; + + sha384_init( &ctx ); + sha384_update( &ctx, input, ilen ); + sha384_final( &ctx, output ); + + memset( &ctx, 0, sizeof( sha384_ctx ) ); +} + +/* + * SHA-384 HMAC context setup + */ +void sha384_hmac_init( sha384_ctx *ctx, unsigned char *key, int keylen ) +{ + int i; + unsigned char sum[64]; + + if( keylen > 128 ) + { + sha384_complete( key, keylen, sum ); + keylen = ( is384 ) ? 48 : 64; + key = sum; + } + + memset( ctx->ipad, 0x36, 128 ); + memset( ctx->opad, 0x5C, 128 ); + + for( i = 0; i < keylen; i++ ) + { + ctx->ipad[i] = (unsigned char)( ctx->ipad[i] ^ key[i] ); + ctx->opad[i] = (unsigned char)( ctx->opad[i] ^ key[i] ); + } + + sha384_init( ctx ); + sha384_update( ctx, ctx->ipad, 128 ); + + memset( sum, 0, sizeof( sum ) ); +} + +/* + * SHA-384 HMAC process buffer + */ +void sha384_hmac_update( sha384_ctx *ctx, + unsigned char *input, int ilen ) +{ + sha384_update( ctx, input, ilen ); +} + +/* + * SHA-384 HMAC final digest + */ +void sha384_hmac_final( sha384_ctx *ctx, unsigned char output[64] ) +{ + int hlen; + unsigned char tmpbuf[64]; + + hlen = ( is384 == 0 ) ? 64 : 48; + + sha384_final( ctx, tmpbuf ); + sha384_init( ctx ); + sha384_update( ctx, ctx->opad, 128 ); + sha384_update( ctx, tmpbuf, hlen ); + sha384_final( ctx, output ); + + memset( tmpbuf, 0, sizeof( tmpbuf ) ); +} + +/* + * output = HMAC-SHA-384( hmac key, input buffer ) + */ +void sha384_hmac_complete( unsigned char *key, int keylen, + unsigned char *input, int ilen, + unsigned char output[64] ) +{ + sha384_ctx ctx; + + sha384_hmac_init( &ctx, key, keylen ); + sha384_hmac_update( &ctx, input, ilen ); + sha384_hmac_final( &ctx, output ); + + memset( &ctx, 0, sizeof( sha384_ctx ) ); +} + +struct digest_algorithm sha384_digest = { + .name = "sha384", + .contextlen = sizeof sha384_digest, + .digestlen = SHA384_DIGEST_LEN, + .init = (digest_init_func)sha384_init, + .update = (digest_update_func)sha384_update, + .final = (digest_final_func)sha384_final, + .complete = (digest_complete_func)sha384_complete, +}; diff --git a/lib/digest/sha512.c b/lib/digest/sha512.c new file mode 100644 index 0000000..1ffd38f --- /dev/null +++ b/lib/digest/sha512.c @@ -0,0 +1,419 @@ +/* + * Copyright (c) 2006-2007 Christophe Devine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Cryb$ + */ +/* + * The SHA-512 Secure Hash Standard was published by NIST in 2002. + * + * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf + */ + +#include "cryb/impl.h" + +#include +#include + +#include +#include + +static int is384 = 0; + +/* + * 64-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT64_BE +#define GET_UINT64_BE(n,b,i) \ +do { \ + (n) = ( (uint64_t) (b)[(i) ] << 56 ) \ + | ( (uint64_t) (b)[(i) + 1] << 48 ) \ + | ( (uint64_t) (b)[(i) + 2] << 40 ) \ + | ( (uint64_t) (b)[(i) + 3] << 32 ) \ + | ( (uint64_t) (b)[(i) + 4] << 24 ) \ + | ( (uint64_t) (b)[(i) + 5] << 16 ) \ + | ( (uint64_t) (b)[(i) + 6] << 8 ) \ + | ( (uint64_t) (b)[(i) + 7] ); \ +} while (0) +#endif + +#ifndef PUT_UINT64_BE +#define PUT_UINT64_BE(n,b,i) \ +do { \ + (b)[(i) ] = (unsigned char) ( (n) >> 56 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 48 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 40 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) >> 32 ); \ + (b)[(i) + 4] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 5] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 6] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 7] = (unsigned char) ( (n) ); \ +} while (0) +#endif + +/* XXX */ +#define UL64(x) x##ULL + +/* + * Round constants + */ +static const uint64_t K[80] = +{ + UL64(0x428A2F98D728AE22), UL64(0x7137449123EF65CD), + UL64(0xB5C0FBCFEC4D3B2F), UL64(0xE9B5DBA58189DBBC), + UL64(0x3956C25BF348B538), UL64(0x59F111F1B605D019), + UL64(0x923F82A4AF194F9B), UL64(0xAB1C5ED5DA6D8118), + UL64(0xD807AA98A3030242), UL64(0x12835B0145706FBE), + UL64(0x243185BE4EE4B28C), UL64(0x550C7DC3D5FFB4E2), + UL64(0x72BE5D74F27B896F), UL64(0x80DEB1FE3B1696B1), + UL64(0x9BDC06A725C71235), UL64(0xC19BF174CF692694), + UL64(0xE49B69C19EF14AD2), UL64(0xEFBE4786384F25E3), + UL64(0x0FC19DC68B8CD5B5), UL64(0x240CA1CC77AC9C65), + UL64(0x2DE92C6F592B0275), UL64(0x4A7484AA6EA6E483), + UL64(0x5CB0A9DCBD41FBD4), UL64(0x76F988DA831153B5), + UL64(0x983E5152EE66DFAB), UL64(0xA831C66D2DB43210), + UL64(0xB00327C898FB213F), UL64(0xBF597FC7BEEF0EE4), + UL64(0xC6E00BF33DA88FC2), UL64(0xD5A79147930AA725), + UL64(0x06CA6351E003826F), UL64(0x142929670A0E6E70), + UL64(0x27B70A8546D22FFC), UL64(0x2E1B21385C26C926), + UL64(0x4D2C6DFC5AC42AED), UL64(0x53380D139D95B3DF), + UL64(0x650A73548BAF63DE), UL64(0x766A0ABB3C77B2A8), + UL64(0x81C2C92E47EDAEE6), UL64(0x92722C851482353B), + UL64(0xA2BFE8A14CF10364), UL64(0xA81A664BBC423001), + UL64(0xC24B8B70D0F89791), UL64(0xC76C51A30654BE30), + UL64(0xD192E819D6EF5218), UL64(0xD69906245565A910), + UL64(0xF40E35855771202A), UL64(0x106AA07032BBD1B8), + UL64(0x19A4C116B8D2D0C8), UL64(0x1E376C085141AB53), + UL64(0x2748774CDF8EEB99), UL64(0x34B0BCB5E19B48A8), + UL64(0x391C0CB3C5C95A63), UL64(0x4ED8AA4AE3418ACB), + UL64(0x5B9CCA4F7763E373), UL64(0x682E6FF3D6B2B8A3), + UL64(0x748F82EE5DEFB2FC), UL64(0x78A5636F43172F60), + UL64(0x84C87814A1F0AB72), UL64(0x8CC702081A6439EC), + UL64(0x90BEFFFA23631E28), UL64(0xA4506CEBDE82BDE9), + UL64(0xBEF9A3F7B2C67915), UL64(0xC67178F2E372532B), + UL64(0xCA273ECEEA26619C), UL64(0xD186B8C721C0C207), + UL64(0xEADA7DD6CDE0EB1E), UL64(0xF57D4F7FEE6ED178), + UL64(0x06F067AA72176FBA), UL64(0x0A637DC5A2C898A6), + UL64(0x113F9804BEF90DAE), UL64(0x1B710B35131C471B), + UL64(0x28DB77F523047D84), UL64(0x32CAAB7B40C72493), + UL64(0x3C9EBE0A15C9BEBC), UL64(0x431D67C49C100D4C), + UL64(0x4CC5D4BECB3E42B6), UL64(0x597F299CFC657E2A), + UL64(0x5FCB6FAB3AD6FAEC), UL64(0x6C44198C4A475817) +}; + +/* + * SHA-512 context setup + */ +void sha512_init( sha512_ctx *ctx ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + if( is384 == 0 ) + { + /* SHA-512 */ + ctx->state[0] = UL64(0x6A09E667F3BCC908); + ctx->state[1] = UL64(0xBB67AE8584CAA73B); + ctx->state[2] = UL64(0x3C6EF372FE94F82B); + ctx->state[3] = UL64(0xA54FF53A5F1D36F1); + ctx->state[4] = UL64(0x510E527FADE682D1); + ctx->state[5] = UL64(0x9B05688C2B3E6C1F); + ctx->state[6] = UL64(0x1F83D9ABFB41BD6B); + ctx->state[7] = UL64(0x5BE0CD19137E2179); + } + else + { + /* SHA-384 */ + ctx->state[0] = UL64(0xCBBB9D5DC1059ED8); + ctx->state[1] = UL64(0x629A292A367CD507); + ctx->state[2] = UL64(0x9159015A3070DD17); + ctx->state[3] = UL64(0x152FECD8F70E5939); + ctx->state[4] = UL64(0x67332667FFC00B31); + ctx->state[5] = UL64(0x8EB44A8768581511); + ctx->state[6] = UL64(0xDB0C2E0D64F98FA7); + ctx->state[7] = UL64(0x47B5481DBEFA4FA4); + } +} + +static void sha512_process( sha512_ctx *ctx, const unsigned char *data ) +{ + int i; + uint64_t temp1, temp2, W[80]; + uint64_t A, B, C, D, E, F, G, H; + +#define SHR(x,n) (x >> n) +#define ROTR(x,n) (SHR(x,n) | (x << (64 - n))) + +#define S0(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHR(x, 7)) +#define S1(x) (ROTR(x,19) ^ ROTR(x,61) ^ SHR(x, 6)) + +#define S2(x) (ROTR(x,28) ^ ROTR(x,34) ^ ROTR(x,39)) +#define S3(x) (ROTR(x,14) ^ ROTR(x,18) ^ ROTR(x,41)) + +#define F0(x,y,z) ((x & y) | (z & (x | y))) +#define F1(x,y,z) (z ^ (x & (y ^ z))) + +#define P(a,b,c,d,e,f,g,h,x,K) \ +{ \ + temp1 = h + S3(e) + F1(e,f,g) + K + x; \ + temp2 = S2(a) + F0(a,b,c); \ + d += temp1; h = temp1 + temp2; \ +} + + for( i = 0; i < 16; i++ ) + { + GET_UINT64_BE( W[i], data, i << 3 ); + } + + for( ; i < 80; i++ ) + { + W[i] = S1(W[i - 2]) + W[i - 7] + + S0(W[i - 15]) + W[i - 16]; + } + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + E = ctx->state[4]; + F = ctx->state[5]; + G = ctx->state[6]; + H = ctx->state[7]; + i = 0; + + do + { + P( A, B, C, D, E, F, G, H, W[i], K[i] ); i++; + P( H, A, B, C, D, E, F, G, W[i], K[i] ); i++; + P( G, H, A, B, C, D, E, F, W[i], K[i] ); i++; + P( F, G, H, A, B, C, D, E, W[i], K[i] ); i++; + P( E, F, G, H, A, B, C, D, W[i], K[i] ); i++; + P( D, E, F, G, H, A, B, C, W[i], K[i] ); i++; + P( C, D, E, F, G, H, A, B, W[i], K[i] ); i++; + P( B, C, D, E, F, G, H, A, W[i], K[i] ); i++; + } + while( i < 80 ); + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; + ctx->state[4] += E; + ctx->state[5] += F; + ctx->state[6] += G; + ctx->state[7] += H; +} + +/* + * SHA-512 process buffer + */ +void sha512_update( sha512_ctx *ctx, const void *input, int ilen ) +{ + int fill; + uint64_t left; + + if( ilen <= 0 ) + return; + + left = ctx->total[0] & 0x7F; + fill = (int)( 128 - left ); + + ctx->total[0] += ilen; + + if( ctx->total[0] < (uint64_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), + (void *) input, fill ); + sha512_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 128 ) + { + sha512_process( ctx, input ); + input += 128; + ilen -= 128; + } + + if( ilen > 0 ) + { + memcpy( (void *) (ctx->buffer + left), + (void *) input, ilen ); + } +} + +static const unsigned char sha512_padding[128] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * SHA-512 final digest + */ +void sha512_final( sha512_ctx *ctx, unsigned char output[64] ) +{ + int last, padn; + uint64_t high, low; + unsigned char msglen[16]; + + high = ( ctx->total[0] >> 61 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT64_BE( high, msglen, 0 ); + PUT_UINT64_BE( low, msglen, 8 ); + + last = (int)( ctx->total[0] & 0x7F ); + padn = ( last < 112 ) ? ( 112 - last ) : ( 240 - last ); + + sha512_update( ctx, (unsigned char *) sha512_padding, padn ); + sha512_update( ctx, msglen, 16 ); + + PUT_UINT64_BE( ctx->state[0], output, 0 ); + PUT_UINT64_BE( ctx->state[1], output, 8 ); + PUT_UINT64_BE( ctx->state[2], output, 16 ); + PUT_UINT64_BE( ctx->state[3], output, 24 ); + PUT_UINT64_BE( ctx->state[4], output, 32 ); + PUT_UINT64_BE( ctx->state[5], output, 40 ); + + if( is384 == 0 ) + { + PUT_UINT64_BE( ctx->state[6], output, 48 ); + PUT_UINT64_BE( ctx->state[7], output, 56 ); + } +} + +/* + * output = SHA-512( input buffer ) + */ +void sha512_complete( const void *input, int ilen, + unsigned char output[64] ) +{ + sha512_ctx ctx; + + sha512_init( &ctx ); + sha512_update( &ctx, input, ilen ); + sha512_final( &ctx, output ); + + memset( &ctx, 0, sizeof( sha512_ctx ) ); +} + +/* + * SHA-512 HMAC context setup + */ +void sha512_hmac_init( sha512_ctx *ctx, unsigned char *key, int keylen ) +{ + int i; + unsigned char sum[64]; + + if( keylen > 128 ) + { + sha512_complete( key, keylen, sum ); + keylen = ( is384 ) ? 48 : 64; + key = sum; + } + + memset( ctx->ipad, 0x36, 128 ); + memset( ctx->opad, 0x5C, 128 ); + + for( i = 0; i < keylen; i++ ) + { + ctx->ipad[i] = (unsigned char)( ctx->ipad[i] ^ key[i] ); + ctx->opad[i] = (unsigned char)( ctx->opad[i] ^ key[i] ); + } + + sha512_init( ctx ); + sha512_update( ctx, ctx->ipad, 128 ); + + memset( sum, 0, sizeof( sum ) ); +} + +/* + * SHA-512 HMAC process buffer + */ +void sha512_hmac_update( sha512_ctx *ctx, + unsigned char *input, int ilen ) +{ + sha512_update( ctx, input, ilen ); +} + +/* + * SHA-512 HMAC final digest + */ +void sha512_hmac_final( sha512_ctx *ctx, unsigned char output[64] ) +{ + int hlen; + unsigned char tmpbuf[64]; + + hlen = ( is384 == 0 ) ? 64 : 48; + + sha512_final( ctx, tmpbuf ); + sha512_init( ctx ); + sha512_update( ctx, ctx->opad, 128 ); + sha512_update( ctx, tmpbuf, hlen ); + sha512_final( ctx, output ); + + memset( tmpbuf, 0, sizeof( tmpbuf ) ); +} + +/* + * output = HMAC-SHA-512( hmac key, input buffer ) + */ +void sha512_hmac_complete( unsigned char *key, int keylen, + unsigned char *input, int ilen, + unsigned char output[64] ) +{ + sha512_ctx ctx; + + sha512_hmac_init( &ctx, key, keylen ); + sha512_hmac_update( &ctx, input, ilen ); + sha512_hmac_final( &ctx, output ); + + memset( &ctx, 0, sizeof( sha512_ctx ) ); +} + +struct digest_algorithm sha512_digest = { + .name = "sha512", + .contextlen = sizeof sha512_digest, + .digestlen = SHA512_DIGEST_LEN, + .init = (digest_init_func)sha512_init, + .update = (digest_update_func)sha512_update, + .final = (digest_final_func)sha512_final, + .complete = (digest_complete_func)sha512_complete, +}; diff --git a/t/Makefile.am b/t/Makefile.am index 219f756..9426ec9 100644 --- a/t/Makefile.am +++ b/t/Makefile.am @@ -45,26 +45,41 @@ TESTS += t_ctype TESTS += t_rfc3986 t_rfc4648 # libcryb-digest -TESTS += t_md5 +TESTS += t_md2 t_md4 t_md5 if WITH_OPENSSL -TESTS += t_md5_openssl +TESTS += t_md4_openssl t_md5_openssl +t_md4_openssl_SOURCES = t_md4.c +t_md4_openssl_CFLAGS = $(OPENSSL_INCLUDES) $(OPENSSL_CFLAGS) +t_md4_openssl_LDADD = $(OPENSSL_LDADD) t_md5_openssl_SOURCES = t_md5.c t_md5_openssl_CFLAGS = $(OPENSSL_INCLUDES) $(OPENSSL_CFLAGS) t_md5_openssl_LDADD = $(OPENSSL_LDADD) endif if WITH_RSAREF -TESTS += t_md5_rsaref +TESTS += t_md2_rsaref t_md5_rsaref +t_md2_rsaref_SOURCES = t_md2.c +t_md2_rsaref_CFLAGS = $(RSAREF_INCLUDES) $(RSAREF_CFLAGS) +t_md2_rsaref_LDADD = $(RSAREF_LDADD) t_md5_rsaref_SOURCES = t_md5.c t_md5_rsaref_CFLAGS = $(RSAREF_INCLUDES) $(RSAREF_CFLAGS) t_md5_rsaref_LDADD = $(RSAREF_LDADD) endif -TESTS += t_sha1 +TESTS += t_sha1 t_sha256 t_sha384 t_sha512 if WITH_OPENSSL -TESTS += t_sha1_openssl +TESTS += t_sha1_openssl t_sha256_openssl t_sha384_openssl t_sha512_openssl t_sha1_openssl_SOURCES = t_sha1.c t_sha1_openssl_CFLAGS = $(OPENSSL_INCLUDES) $(OPENSSL_CFLAGS) t_sha1_openssl_LDADD = $(OPENSSL_LDADD) +t_sha256_openssl_SOURCES = t_sha256.c +t_sha256_openssl_CFLAGS = $(OPENSSL_INCLUDES) $(OPENSSL_CFLAGS) +t_sha256_openssl_LDADD = $(OPENSSL_LDADD) +t_sha384_openssl_SOURCES = t_sha384.c +t_sha384_openssl_CFLAGS = $(OPENSSL_INCLUDES) $(OPENSSL_CFLAGS) +t_sha384_openssl_LDADD = $(OPENSSL_LDADD) +t_sha512_openssl_SOURCES = t_sha512.c +t_sha512_openssl_CFLAGS = $(OPENSSL_INCLUDES) $(OPENSSL_CFLAGS) +t_sha512_openssl_LDADD = $(OPENSSL_LDADD) endif # libcryb-mac diff --git a/t/t_md2.c b/t/t_md2.c new file mode 100644 index 0000000..05f979e --- /dev/null +++ b/t/t_md2.c @@ -0,0 +1,257 @@ +/*- + * Copyright (c) 2012 Universitetet i Oslo + * Copyright (c) 2012-2014 Dag-Erling Smørgrav + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Author: Dag-Erling Smørgrav + * Sponsor: the University of Oslo + * + * $Cryb$ + */ + +#include "cryb/impl.h" + +#include +#include +#include +#include +#include +#include + +#include "t.h" + +#if WITH_RSAREF + +#include + +#define MD2_DIGEST_LEN 16 + +static void +t_md2_complete(const void *msg, size_t msglen, uint8_t *digest) +{ + MD2_CTX ctx; + + MD2Init(&ctx); + MD2Update(&ctx, (unsigned char *)(uintptr_t)msg, msglen); + MD2Final(digest, &ctx); +} + +#else + +#include + +#define t_md2_complete(msg, msglen, digest) \ + md2_complete(msg, msglen, digest) + +#endif + +/* + * Test vectors from RFC 1319 + */ +static struct t_vector { + const char *msg; + const uint8_t digest[MD2_DIGEST_LEN]; +} t_md2_vectors[] = { + { + "", + { + 0x83, 0x50, 0xe5, 0xa3, 0xe2, 0x4c, 0x15, 0x3d, + 0xf2, 0x27, 0x5c, 0x9f, 0x80, 0x69, 0x27, 0x73, + } + }, + { + "a", + { + 0x32, 0xec, 0x01, 0xec, 0x4a, 0x6d, 0xac, 0x72, + 0xc0, 0xab, 0x96, 0xfb, 0x34, 0xc0, 0xb5, 0xd1, + } + }, + { + "abc", + { + 0xda, 0x85, 0x3b, 0x0d, 0x3f, 0x88, 0xd9, 0x9b, + 0x30, 0x28, 0x3a, 0x69, 0xe6, 0xde, 0xd6, 0xbb, + } + }, + { + "message digest", + { + 0xab, 0x4f, 0x49, 0x6b, 0xfb, 0x2a, 0x53, 0x0b, + 0x21, 0x9f, 0xf3, 0x30, 0x31, 0xfe, 0x06, 0xb0, + } + }, + { + "abcdefghijklmnopqrstuvwxyz", + { + 0x4e, 0x8d, 0xdf, 0xf3, 0x65, 0x02, 0x92, 0xab, + 0x5a, 0x41, 0x08, 0xc3, 0xaa, 0x47, 0x94, 0x0b, + } + }, + { + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789", + { + 0xda, 0x33, 0xde, 0xf2, 0xa4, 0x2d, 0xf1, 0x39, + 0x75, 0x35, 0x28, 0x46, 0xc3, 0x03, 0x38, 0xcd, + } + }, + { + "1234567890123456789012345678901234567890" + "1234567890123456789012345678901234567890", + { + 0xd5, 0x97, 0x6f, 0x79, 0xd8, 0x3d, 0x3a, 0x0d, + 0xc9, 0x80, 0x6c, 0x3c, 0x66, 0xf3, 0xef, 0xd8, + } + }, +}; + +/* + * Unit test: compute the MD2 sum of the specified string and compare it + * to the expected result. + */ +static int +t_md2_vector(char **desc CRYB_UNUSED, void *arg) +{ + struct t_vector *vector = (struct t_vector *)arg; + uint8_t digest[MD2_DIGEST_LEN]; + + t_md2_complete(vector->msg, strlen(vector->msg), digest); + if (memcmp(digest, vector->digest, MD2_DIGEST_LEN) != 0) { + t_verbose("expected "); + t_verbose_hex(vector->digest, MD2_DIGEST_LEN); + t_verbose("\n"); + t_verbose("got "); + t_verbose_hex(digest, MD2_DIGEST_LEN); + t_verbose("\n"); + return (0); + } + return (1); +} + +#ifdef BENCHMARKS +/* + * Performance test: measure the time spent computing the MD2 sum of a + * message of the specified length. + */ +#define T_PERF_ITERATIONS 1000 +static int +t_md2_perf(char **desc, void *arg) +{ + struct timespec ts, te; + unsigned long ns; + uint8_t digest[MD2_DIGEST_LEN]; + char *msg, *comment; + size_t msglen = *(size_t *)arg; + + if ((msg = calloc(1, msglen)) == NULL) + err(1, "calloc()"); + clock_gettime(CLOCK_MONOTONIC_PRECISE, &ts); + for (int i = 0; i < T_PERF_ITERATIONS; ++i) + t_md2_complete(msg, msglen, digest); + clock_gettime(CLOCK_MONOTONIC_PRECISE, &te); + free(msg); + ns = te.tv_sec * 1000000000LU + te.tv_nsec; + ns -= ts.tv_sec * 1000000000LU + ts.tv_nsec; + asprintf(&comment, "%zu bytes: %d iterations in %'lu ns", + msglen, T_PERF_ITERATIONS, ns); + if (comment == NULL) + err(1, "asprintf()"); + *desc = comment; + return (1); +} +#endif + + +#if !defined(WITH_RSAREF) +/* + * Various corner cases and error conditions + */ +static int +t_md2_short_updates(char **desc CRYB_UNUSED, void *arg) +{ + struct t_vector *vector = (struct t_vector *)arg; + uint8_t digest[MD2_DIGEST_LEN]; + md2_ctx ctx; + int i, len; + + md2_init(&ctx); + len = strlen(vector->msg); + for (i = 0; i + 5 < len; i += 5) + md2_update(&ctx, vector->msg + i, 5); + md2_update(&ctx, vector->msg + i, len - i); + md2_final(&ctx, digest); + return (memcmp(digest, vector->digest, MD2_DIGEST_LEN) == 0); +} +#endif + + +/*************************************************************************** + * Boilerplate + */ + +int +t_prepare(int argc, char *argv[]) +{ + int i, n; + + (void)argc; + (void)argv; + n = sizeof t_md2_vectors / sizeof t_md2_vectors[0]; + for (i = 0; i < n; ++i) + t_add_test(t_md2_vector, &t_md2_vectors[i], + "RFC 1321 test vector %d", i + 1); +#if !defined(WITH_RSAREF) + /* + * Run test vector 7 (which is 80 characters long) 5 characters at + * a time. This tests a) appending data to an underfull block and + * b) appending more data to an underfull block than it has room + * for (since 64 % 5 != 0). Test vector 7 already exercised the + * code path for computing a block directly from source (without + * copying it in), and all the test vectors except vector 1 + * exercised the general case of copying a small amount of data in + * without crossing the block boundary. + */ + t_add_test(t_md2_short_updates, &t_md2_vectors[6], + "multiple short updates"); +#endif +#ifdef BENCHMARKS + static size_t one = 1, thousand = 1000, million = 1000000; + t_add_test(t_md2_perf, &one, + "performance test (1 byte)"); + t_add_test(t_md2_perf, &thousand, + "performance test (1,000 bytes)"); + t_add_test(t_md2_perf, &million, + "performance test (1,000,000 bytes)"); +#endif + return (0); +} + +void +t_cleanup(void) +{ +} diff --git a/t/t_md4.c b/t/t_md4.c new file mode 100644 index 0000000..0621766 --- /dev/null +++ b/t/t_md4.c @@ -0,0 +1,273 @@ +/*- + * Copyright (c) 2012 Universitetet i Oslo + * Copyright (c) 2012-2014 Dag-Erling Smørgrav + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Author: Dag-Erling Smørgrav + * Sponsor: the University of Oslo + * + * $Cryb$ + */ + +#include "cryb/impl.h" + +#include +#include +#include +#include +#include +#include + +#include "t.h" + +#if WITH_OPENSSL + +#include + +#define MD4_DIGEST_LEN MD4_DIGEST_LENGTH + +static void +t_md4_complete(const void *msg, size_t msglen, uint8_t *digest) +{ + MD4_CTX ctx; + + MD4_Init(&ctx); + MD4_Update(&ctx, msg, msglen); + MD4_Final(digest, &ctx); +} + +#elif WITH_RSAREF + +#include + +#define MD4_DIGEST_LEN 16 + +static void +t_md4_complete(const void *msg, size_t msglen, uint8_t *digest) +{ + MD4_CTX ctx; + + MD4Init(&ctx); + MD4Update(&ctx, (unsigned char *)(uintptr_t)msg, msglen); + MD4Final(digest, &ctx); +} + +#else + +#include + +#define t_md4_complete(msg, msglen, digest) \ + md4_complete(msg, msglen, digest) + +#endif + +/* + * Test vectors from RFC 1320 + */ +static struct t_vector { + const char *msg; + const uint8_t digest[MD4_DIGEST_LEN]; +} t_md4_vectors[] = { + { + "", + { + 0x31, 0xd6, 0xcf, 0xe0, 0xd1, 0x6a, 0xe9, 0x31, + 0xb7, 0x3c, 0x59, 0xd7, 0xe0, 0xc0, 0x89, 0xc0, + } + }, + { + "a", + { + 0xbd, 0xe5, 0x2c, 0xb3, 0x1d, 0xe3, 0x3e, 0x46, + 0x24, 0x5e, 0x05, 0xfb, 0xdb, 0xd6, 0xfb, 0x24, + } + }, + { + "abc", + { + 0xa4, 0x48, 0x01, 0x7a, 0xaf, 0x21, 0xd8, 0x52, + 0x5f, 0xc1, 0x0a, 0xe8, 0x7a, 0xa6, 0x72, 0x9d, + } + }, + { + "message digest", + { + 0xd9, 0x13, 0x0a, 0x81, 0x64, 0x54, 0x9f, 0xe8, + 0x18, 0x87, 0x48, 0x06, 0xe1, 0xc7, 0x01, 0x4b, + } + }, + { + "abcdefghijklmnopqrstuvwxyz", + { + 0xd7, 0x9e, 0x1c, 0x30, 0x8a, 0xa5, 0xbb, 0xcd, + 0xee, 0xa8, 0xed, 0x63, 0xdf, 0x41, 0x2d, 0xa9, + } + }, + { + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789", + { + 0x04, 0x3f, 0x85, 0x82, 0xf2, 0x41, 0xdb, 0x35, + 0x1c, 0xe6, 0x27, 0xe1, 0x53, 0xe7, 0xf0, 0xe4, + } + }, + { + "1234567890123456789012345678901234567890" + "1234567890123456789012345678901234567890", + { + 0xe3, 0x3b, 0x4d, 0xdc, 0x9c, 0x38, 0xf2, 0x19, + 0x9c, 0x3e, 0x7b, 0x16, 0x4f, 0xcc, 0x05, 0x36, + } + }, +}; + +/* + * Unit test: compute the MD4 sum of the specified string and compare it + * to the expected result. + */ +static int +t_md4_vector(char **desc CRYB_UNUSED, void *arg) +{ + struct t_vector *vector = (struct t_vector *)arg; + uint8_t digest[MD4_DIGEST_LEN]; + + t_md4_complete(vector->msg, strlen(vector->msg), digest); + if (memcmp(digest, vector->digest, MD4_DIGEST_LEN) != 0) { + t_verbose("expected "); + t_verbose_hex(vector->digest, MD4_DIGEST_LEN); + t_verbose("\n"); + t_verbose("got "); + t_verbose_hex(digest, MD4_DIGEST_LEN); + t_verbose("\n"); + return (0); + } + return (1); +} + +#ifdef BENCHMARKS +/* + * Performance test: measure the time spent computing the MD4 sum of a + * message of the specified length. + */ +#define T_PERF_ITERATIONS 1000 +static int +t_md4_perf(char **desc, void *arg) +{ + struct timespec ts, te; + unsigned long ns; + uint8_t digest[MD4_DIGEST_LEN]; + char *msg, *comment; + size_t msglen = *(size_t *)arg; + + if ((msg = calloc(1, msglen)) == NULL) + err(1, "calloc()"); + clock_gettime(CLOCK_MONOTONIC_PRECISE, &ts); + for (int i = 0; i < T_PERF_ITERATIONS; ++i) + t_md4_complete(msg, msglen, digest); + clock_gettime(CLOCK_MONOTONIC_PRECISE, &te); + free(msg); + ns = te.tv_sec * 1000000000LU + te.tv_nsec; + ns -= ts.tv_sec * 1000000000LU + ts.tv_nsec; + asprintf(&comment, "%zu bytes: %d iterations in %'lu ns", + msglen, T_PERF_ITERATIONS, ns); + if (comment == NULL) + err(1, "asprintf()"); + *desc = comment; + return (1); +} +#endif + + +#if !defined(WITH_OPENSSL) && !defined(WITH_RSAREF) +/* + * Various corner cases and error conditions + */ +static int +t_md4_short_updates(char **desc CRYB_UNUSED, void *arg) +{ + struct t_vector *vector = (struct t_vector *)arg; + uint8_t digest[MD4_DIGEST_LEN]; + md4_ctx ctx; + int i, len; + + md4_init(&ctx); + len = strlen(vector->msg); + for (i = 0; i + 5 < len; i += 5) + md4_update(&ctx, vector->msg + i, 5); + md4_update(&ctx, vector->msg + i, len - i); + md4_final(&ctx, digest); + return (memcmp(digest, vector->digest, MD4_DIGEST_LEN) == 0); +} +#endif + + +/*************************************************************************** + * Boilerplate + */ + +int +t_prepare(int argc, char *argv[]) +{ + int i, n; + + (void)argc; + (void)argv; + n = sizeof t_md4_vectors / sizeof t_md4_vectors[0]; + for (i = 0; i < n; ++i) + t_add_test(t_md4_vector, &t_md4_vectors[i], + "RFC 1321 test vector %d", i + 1); +#if !defined(WITH_OPENSSL) && !defined(WITH_RSAREF) + /* + * Run test vector 7 (which is 80 characters long) 5 characters at + * a time. This tests a) appending data to an underfull block and + * b) appending more data to an underfull block than it has room + * for (since 64 % 5 != 0). Test vector 7 already exercised the + * code path for computing a block directly from source (without + * copying it in), and all the test vectors except vector 1 + * exercised the general case of copying a small amount of data in + * without crossing the block boundary. + */ + t_add_test(t_md4_short_updates, &t_md4_vectors[6], + "multiple short updates"); +#endif +#ifdef BENCHMARKS + static size_t one = 1, thousand = 1000, million = 1000000; + t_add_test(t_md4_perf, &one, + "performance test (1 byte)"); + t_add_test(t_md4_perf, &thousand, + "performance test (1,000 bytes)"); + t_add_test(t_md4_perf, &million, + "performance test (1,000,000 bytes)"); +#endif + return (0); +} + +void +t_cleanup(void) +{ +} diff --git a/t/t_sha256.c b/t/t_sha256.c new file mode 100644 index 0000000..2da9e25 --- /dev/null +++ b/t/t_sha256.c @@ -0,0 +1,275 @@ +/*- + * Copyright (c) 2012 Universitetet i Oslo + * Copyright (c) 2012-2014 Dag-Erling Smørgrav + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Author: Dag-Erling Smørgrav + * Sponsor: the University of Oslo + * + * $Cryb$ + */ + +#include "cryb/impl.h" + +#include +#include +#include +#include +#include +#include + +#include "t.h" + +#if WITH_OPENSSL + +#include + +#define SHA256_DIGEST_LEN SHA256_DIGEST_LENGTH + +static void +t_sha256_complete(const void *msg, size_t msglen, uint8_t *digest) +{ + SHA256_CTX ctx; + + SHA256_Init(&ctx); + SHA256_Update(&ctx, msg, msglen); + SHA256_Final(digest, &ctx); +} + +#else + +#include + +#define t_sha256_complete(msg, msglen, digest) \ + sha256_complete(msg, msglen, digest) + +#endif + +static struct t_vector { + const char *desc; + const char *msg; + const uint8_t digest[SHA256_DIGEST_LEN]; +} t_sha256_vectors[] = { + { + "zero-length message", + "", + { + 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, + 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, + 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, + 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55, + } + }, + { + "FIPS 180-2 B.1 (one-block message)", + "abc", + { + 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, + 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, + 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, + 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad, + } + }, + { + /* + * This message is *just* long enough to necessitate a + * second block, which consists entirely of padding. + */ + "FIPS 180-2 B.2 (multi-block message)", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + { + 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, + 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39, + 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, + 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1, + } + }, + { + /* + * 1,000,000 x 'a', filled in by t_prepare() + */ + "FIPS 180-2 B.3 (long message)", + NULL, + { + 0xcd, 0xc7, 0x6e, 0x5c, 0x99, 0x14, 0xfb, 0x92, + 0x81, 0xa1, 0xc7, 0xe2, 0x84, 0xd7, 0x3e, 0x67, + 0xf1, 0x80, 0x9a, 0x48, 0xa4, 0x97, 0x20, 0x0e, + 0x04, 0x6d, 0x39, 0xcc, 0xc7, 0x11, 0x2c, 0xd0, + }, + }, + { + /* + * One of the MD5 test vectors, included for the "short + * update" test. + */ + "\"1234567890\"x8", + "1234567890123456789012345678901234567890" + "1234567890123456789012345678901234567890", + { + 0xf3, 0x71, 0xbc, 0x4a, 0x31, 0x1f, 0x2b, 0x00, + 0x9e, 0xef, 0x95, 0x2d, 0xd8, 0x3c, 0xa8, 0x0e, + 0x2b, 0x60, 0x02, 0x6c, 0x8e, 0x93, 0x55, 0x92, + 0xd0, 0xf9, 0xc3, 0x08, 0x45, 0x3c, 0x81, 0x3e, + }, + }, +}; + +/* + * Unit test: compute the SHA256 sum of the specified string and compare it + * to the expected result. + */ +static int +t_sha256_vector(char **desc CRYB_UNUSED, void *arg) +{ + struct t_vector *vector = (struct t_vector *)arg; + uint8_t digest[SHA256_DIGEST_LEN]; + char *msg; + + if (vector->msg) { + t_sha256_complete(vector->msg, strlen(vector->msg), digest); + } else { + /* special case for FIPS test vector 3 */ + if ((msg = malloc(1000000)) == NULL) + err(1, "malloc()"); + memset(msg, 'a', 1000000); + t_sha256_complete(msg, 1000000, digest); + free(msg); + } + if (memcmp(digest, vector->digest, SHA256_DIGEST_LEN) != 0) { + t_verbose("expected "); + t_verbose_hex(vector->digest, SHA256_DIGEST_LEN); + t_verbose("\n"); + t_verbose("got "); + t_verbose_hex(digest, SHA256_DIGEST_LEN); + t_verbose("\n"); + return (0); + } + return (1); +} + + +#if !defined(WITH_OPENSSL) && !defined(WITH_RSAREF) +/* + * Various corner cases and error conditions + */ +static int +t_sha256_short_updates(char **desc CRYB_UNUSED, void *arg) +{ + struct t_vector *vector = (struct t_vector *)arg; + uint8_t digest[SHA256_DIGEST_LEN]; + sha256_ctx ctx; + int i, len; + + sha256_init(&ctx); + len = strlen(vector->msg); + for (i = 0; i + 5 < len; i += 5) + sha256_update(&ctx, vector->msg + i, 5); + sha256_update(&ctx, vector->msg + i, len - i); + sha256_final(&ctx, digest); + return (memcmp(digest, vector->digest, SHA256_DIGEST_LEN) == 0); +} +#endif + +#ifdef BENCHMARKS +/* + * Performance test: measure the time spent computing the SHA256 sum of a + * message of the specified length. + */ +#define T_PERF_ITERATIONS 1000 +static int +t_sha256_perf(char **desc, void *arg) +{ + struct timespec ts, te; + unsigned long ns; + uint8_t digest[SHA256_DIGEST_LEN]; + char *msg, *comment; + size_t msglen = *(size_t *)arg; + + if ((msg = calloc(1, msglen)) == NULL) + err(1, "calloc()"); + clock_gettime(CLOCK_MONOTONIC_PRECISE, &ts); + for (int i = 0; i < T_PERF_ITERATIONS; ++i) + t_sha256_complete(msg, msglen, digest); + clock_gettime(CLOCK_MONOTONIC_PRECISE, &te); + free(msg); + ns = te.tv_sec * 1000000000LU + te.tv_nsec; + ns -= ts.tv_sec * 1000000000LU + ts.tv_nsec; + asprintf(&comment, "%zu bytes: %d iterations in %'lu ns", + msglen, T_PERF_ITERATIONS, ns); + if (comment == NULL) + err(1, "asprintf()"); + *desc = comment; + return (1); +} +#endif + + +/*************************************************************************** + * Boilerplate + */ + +int +t_prepare(int argc, char *argv[]) +{ + int i, n; + + (void)argc; + (void)argv; + n = sizeof t_sha256_vectors / sizeof t_sha256_vectors[0]; + for (i = 0; i < n; ++i) + t_add_test(t_sha256_vector, &t_sha256_vectors[i], + t_sha256_vectors[i].desc); +#if !defined(WITH_OPENSSL) && !defined(WITH_RSAREF) + /* + * Run test vector 5 (md5 test vector 7, which is 80 characters + * long) 5 characters at a time. This tests a) appending data to + * an underfull block and b) appending more data to an underfull + * block than it has room for (since 64 % 5 != 0). Test vector 4 + * and 5 already exercised the code path for computing a block + * directly from source (without copying it in), and all the test + * vectors except vector 1 exercised the general case of copying a + * small amount of data in without crossing the block boundary. + */ + t_add_test(t_sha256_short_updates, &t_sha256_vectors[4], + "multiple short updates"); +#endif +#ifdef BENCHMARKS + static size_t one = 1, thousand = 1000, million = 1000000; + t_add_test(t_sha256_perf, &one, + "performance test (1 byte)"); + t_add_test(t_sha256_perf, &thousand, + "performance test (1,000 bytes)"); + t_add_test(t_sha256_perf, &million, + "performance test (1,000,000 bytes)"); +#endif + return (0); +} + +void +t_cleanup(void) +{ +} diff --git a/t/t_sha384.c b/t/t_sha384.c new file mode 100644 index 0000000..1ff9bf3 --- /dev/null +++ b/t/t_sha384.c @@ -0,0 +1,286 @@ +/*- + * Copyright (c) 2012 Universitetet i Oslo + * Copyright (c) 2012-2014 Dag-Erling Smørgrav + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Author: Dag-Erling Smørgrav + * Sponsor: the University of Oslo + * + * $Cryb: trunk/t/t_sha384.c 3 2014-07-04 11:20:46Z des $ + */ + +#include "cryb/impl.h" + +#include +#include +#include +#include +#include +#include + +#include "t.h" + +#if WITH_OPENSSL + +#include + +#define SHA384_DIGEST_LEN SHA384_DIGEST_LENGTH + +static void +t_sha384_complete(const void *msg, size_t msglen, uint8_t *digest) +{ + SHA512_CTX ctx; /* yes, 512 is correct */ + + SHA384_Init(&ctx); + SHA384_Update(&ctx, msg, msglen); + SHA384_Final(digest, &ctx); +} + +#else + +#include + +#define t_sha384_complete(msg, msglen, digest) \ + sha384_complete(msg, msglen, digest) + +#endif + +static struct t_vector { + const char *desc; + const char *msg; + const uint8_t digest[SHA384_DIGEST_LEN]; +} t_sha384_vectors[] = { + { + "zero-length message", + "", + { + 0x38, 0xb0, 0x60, 0xa7, 0x51, 0xac, 0x96, 0x38, + 0x4c, 0xd9, 0x32, 0x7e, 0xb1, 0xb1, 0xe3, 0x6a, + 0x21, 0xfd, 0xb7, 0x11, 0x14, 0xbe, 0x07, 0x43, + 0x4c, 0x0c, 0xc7, 0xbf, 0x63, 0xf6, 0xe1, 0xda, + 0x27, 0x4e, 0xde, 0xbf, 0xe7, 0x6f, 0x65, 0xfb, + 0xd5, 0x1a, 0xd2, 0xf1, 0x48, 0x98, 0xb9, 0x5b, + } + }, + { + "FIPS 180-2 D.1 (one-block message)", + "abc", + { + 0xcb, 0x00, 0x75, 0x3f, 0x45, 0xa3, 0x5e, 0x8b, + 0xb5, 0xa0, 0x3d, 0x69, 0x9a, 0xc6, 0x50, 0x07, + 0x27, 0x2c, 0x32, 0xab, 0x0e, 0xde, 0xd1, 0x63, + 0x1a, 0x8b, 0x60, 0x5a, 0x43, 0xff, 0x5b, 0xed, + 0x80, 0x86, 0x07, 0x2b, 0xa1, 0xe7, 0xcc, 0x23, + 0x58, 0xba, 0xec, 0xa1, 0x34, 0xc8, 0x25, 0xa7, + } + }, + { + /* + * This message is *just* long enough to necessitate a + * second block, which consists entirely of padding. + */ + "FIPS 180-2 D.2 (multi-block message)", + "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" + "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", + { + 0x09, 0x33, 0x0c, 0x33, 0xf7, 0x11, 0x47, 0xe8, + 0x3d, 0x19, 0x2f, 0xc7, 0x82, 0xcd, 0x1b, 0x47, + 0x53, 0x11, 0x1b, 0x17, 0x3b, 0x3b, 0x05, 0xd2, + 0x2f, 0xa0, 0x80, 0x86, 0xe3, 0xb0, 0xf7, 0x12, + 0xfc, 0xc7, 0xc7, 0x1a, 0x55, 0x7e, 0x2d, 0xb9, + 0x66, 0xc3, 0xe9, 0xfa, 0x91, 0x74, 0x60, 0x39, + } + }, + { + /* + * 1,000,000 x 'a', filled in by t_prepare() + */ + "FIPS 180-2 D.3 (long message)", + NULL, + { + 0x9d, 0x0e, 0x18, 0x09, 0x71, 0x64, 0x74, 0xcb, + 0x08, 0x6e, 0x83, 0x4e, 0x31, 0x0a, 0x4a, 0x1c, + 0xed, 0x14, 0x9e, 0x9c, 0x00, 0xf2, 0x48, 0x52, + 0x79, 0x72, 0xce, 0xc5, 0x70, 0x4c, 0x2a, 0x5b, + 0x07, 0xb8, 0xb3, 0xdc, 0x38, 0xec, 0xc4, 0xeb, + 0xae, 0x97, 0xdd, 0xd8, 0x7f, 0x3d, 0x89, 0x85, + }, + }, + { + /* + * One of the MD5 test vectors, included for the "short + * update" test. + */ + "\"1234567890\"x8", + "1234567890123456789012345678901234567890" + "1234567890123456789012345678901234567890", + { + 0xb1, 0x29, 0x32, 0xb0, 0x62, 0x7d, 0x1c, 0x06, + 0x09, 0x42, 0xf5, 0x44, 0x77, 0x64, 0x15, 0x56, + 0x55, 0xbd, 0x4d, 0xa0, 0xc9, 0xaf, 0xa6, 0xdd, + 0x9b, 0x9e, 0xf5, 0x31, 0x29, 0xaf, 0x1b, 0x8f, + 0xb0, 0x19, 0x59, 0x96, 0xd2, 0xde, 0x9c, 0xa0, + 0xdf, 0x9d, 0x82, 0x1f, 0xfe, 0xe6, 0x70, 0x26, + }, + }, +}; + +/* + * Unit test: compute the SHA384 sum of the specified string and compare it + * to the expected result. + */ +static int +t_sha384_vector(char **desc CRYB_UNUSED, void *arg) +{ + struct t_vector *vector = (struct t_vector *)arg; + uint8_t digest[SHA384_DIGEST_LEN]; + char *msg; + + if (vector->msg) { + t_sha384_complete(vector->msg, strlen(vector->msg), digest); + } else { + /* special case for FIPS test vector 3 */ + if ((msg = malloc(1000000)) == NULL) + err(1, "malloc()"); + memset(msg, 'a', 1000000); + t_sha384_complete(msg, 1000000, digest); + free(msg); + } + if (memcmp(digest, vector->digest, SHA384_DIGEST_LEN) != 0) { + t_verbose("expected "); + t_verbose_hex(vector->digest, SHA384_DIGEST_LEN); + t_verbose("\n"); + t_verbose("got "); + t_verbose_hex(digest, SHA384_DIGEST_LEN); + t_verbose("\n"); + return (0); + } + return (1); +} + + +#if !defined(WITH_OPENSSL) && !defined(WITH_RSAREF) +/* + * Various corner cases and error conditions + */ +static int +t_sha384_short_updates(char **desc CRYB_UNUSED, void *arg) +{ + struct t_vector *vector = (struct t_vector *)arg; + uint8_t digest[SHA384_DIGEST_LEN]; + sha384_ctx ctx; + int i, len; + + sha384_init(&ctx); + len = strlen(vector->msg); + for (i = 0; i + 5 < len; i += 5) + sha384_update(&ctx, vector->msg + i, 5); + sha384_update(&ctx, vector->msg + i, len - i); + sha384_final(&ctx, digest); + return (memcmp(digest, vector->digest, SHA384_DIGEST_LEN) == 0); +} +#endif + +#ifdef BENCHMARKS +/* + * Performance test: measure the time spent computing the SHA384 sum of a + * message of the specified length. + */ +#define T_PERF_ITERATIONS 1000 +static int +t_sha384_perf(char **desc, void *arg) +{ + struct timespec ts, te; + unsigned long ns; + uint8_t digest[SHA384_DIGEST_LEN]; + char *msg, *comment; + size_t msglen = *(size_t *)arg; + + if ((msg = calloc(1, msglen)) == NULL) + err(1, "calloc()"); + clock_gettime(CLOCK_MONOTONIC_PRECISE, &ts); + for (int i = 0; i < T_PERF_ITERATIONS; ++i) + t_sha384_complete(msg, msglen, digest); + clock_gettime(CLOCK_MONOTONIC_PRECISE, &te); + free(msg); + ns = te.tv_sec * 1000000000LU + te.tv_nsec; + ns -= ts.tv_sec * 1000000000LU + ts.tv_nsec; + asprintf(&comment, "%zu bytes: %d iterations in %'lu ns", + msglen, T_PERF_ITERATIONS, ns); + if (comment == NULL) + err(1, "asprintf()"); + *desc = comment; + return (1); +} +#endif + + +/*************************************************************************** + * Boilerplate + */ + +int +t_prepare(int argc, char *argv[]) +{ + int i, n; + + (void)argc; + (void)argv; + n = sizeof t_sha384_vectors / sizeof t_sha384_vectors[0]; + for (i = 0; i < n; ++i) + t_add_test(t_sha384_vector, &t_sha384_vectors[i], + t_sha384_vectors[i].desc); +#if !defined(WITH_OPENSSL) && !defined(WITH_RSAREF) + /* + * Run test vector 5 (md5 test vector 7, which is 80 characters + * long) 5 characters at a time. This tests a) appending data to + * an underfull block and b) appending more data to an underfull + * block than it has room for (since 64 % 5 != 0). Test vector 4 + * and 5 already exercised the code path for computing a block + * directly from source (without copying it in), and all the test + * vectors except vector 1 exercised the general case of copying a + * small amount of data in without crossing the block boundary. + */ + t_add_test(t_sha384_short_updates, &t_sha384_vectors[4], + "multiple short updates"); +#endif +#ifdef BENCHMARKS + static size_t one = 1, thousand = 1000, million = 1000000; + t_add_test(t_sha384_perf, &one, + "performance test (1 byte)"); + t_add_test(t_sha384_perf, &thousand, + "performance test (1,000 bytes)"); + t_add_test(t_sha384_perf, &million, + "performance test (1,000,000 bytes)"); +#endif + return (0); +} + +void +t_cleanup(void) +{ +} diff --git a/t/t_sha512.c b/t/t_sha512.c new file mode 100644 index 0000000..38acd7d --- /dev/null +++ b/t/t_sha512.c @@ -0,0 +1,296 @@ +/*- + * Copyright (c) 2012 Universitetet i Oslo + * Copyright (c) 2012-2014 Dag-Erling Smørgrav + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Author: Dag-Erling Smørgrav + * Sponsor: the University of Oslo + * + * $Cryb$ + */ + +#include "cryb/impl.h" + +#include +#include +#include +#include +#include +#include + +#include "t.h" + +#if WITH_OPENSSL + +#include + +#define SHA512_DIGEST_LEN SHA512_DIGEST_LENGTH + +static void +t_sha512_complete(const void *msg, size_t msglen, uint8_t *digest) +{ + SHA512_CTX ctx; + + SHA512_Init(&ctx); + SHA512_Update(&ctx, msg, msglen); + SHA512_Final(digest, &ctx); +} + +#else + +#include + +#define t_sha512_complete(msg, msglen, digest) \ + sha512_complete(msg, msglen, digest) + +#endif + +static struct t_vector { + const char *desc; + const char *msg; + const uint8_t digest[SHA512_DIGEST_LEN]; +} t_sha512_vectors[] = { + { + "zero-length message", + "", + { + 0xcf, 0x83, 0xe1, 0x35, 0x7e, 0xef, 0xb8, 0xbd, + 0xf1, 0x54, 0x28, 0x50, 0xd6, 0x6d, 0x80, 0x07, + 0xd6, 0x20, 0xe4, 0x05, 0x0b, 0x57, 0x15, 0xdc, + 0x83, 0xf4, 0xa9, 0x21, 0xd3, 0x6c, 0xe9, 0xce, + 0x47, 0xd0, 0xd1, 0x3c, 0x5d, 0x85, 0xf2, 0xb0, + 0xff, 0x83, 0x18, 0xd2, 0x87, 0x7e, 0xec, 0x2f, + 0x63, 0xb9, 0x31, 0xbd, 0x47, 0x41, 0x7a, 0x81, + 0xa5, 0x38, 0x32, 0x7a, 0xf9, 0x27, 0xda, 0x3e, + } + }, + { + "FIPS 180-2 C.1 (one-block message)", + "abc", + { + 0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, + 0xcc, 0x41, 0x73, 0x49, 0xae, 0x20, 0x41, 0x31, + 0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2, + 0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a, + 0x21, 0x92, 0x99, 0x2a, 0x27, 0x4f, 0xc1, 0xa8, + 0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd, + 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e, + 0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4, 0x9f, + } + }, + { + /* + * This message is *just* long enough to necessitate a + * second block, which consists entirely of padding. + */ + "FIPS 180-2 C.2 (multi-block message)", + "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" + "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", + { + 0x8e, 0x95, 0x9b, 0x75, 0xda, 0xe3, 0x13, 0xda, + 0x8c, 0xf4, 0xf7, 0x28, 0x14, 0xfc, 0x14, 0x3f, + 0x8f, 0x77, 0x79, 0xc6, 0xeb, 0x9f, 0x7f, 0xa1, + 0x72, 0x99, 0xae, 0xad, 0xb6, 0x88, 0x90, 0x18, + 0x50, 0x1d, 0x28, 0x9e, 0x49, 0x00, 0xf7, 0xe4, + 0x33, 0x1b, 0x99, 0xde, 0xc4, 0xb5, 0x43, 0x3a, + 0xc7, 0xd3, 0x29, 0xee, 0xb6, 0xdd, 0x26, 0x54, + 0x5e, 0x96, 0xe5, 0x5b, 0x87, 0x4b, 0xe9, 0x09, + } + }, + { + /* + * 1,000,000 x 'a', filled in by t_prepare() + */ + "FIPS 180-2 C.3 (long message)", + NULL, + { + 0xe7, 0x18, 0x48, 0x3d, 0x0c, 0xe7, 0x69, 0x64, + 0x4e, 0x2e, 0x42, 0xc7, 0xbc, 0x15, 0xb4, 0x63, + 0x8e, 0x1f, 0x98, 0xb1, 0x3b, 0x20, 0x44, 0x28, + 0x56, 0x32, 0xa8, 0x03, 0xaf, 0xa9, 0x73, 0xeb, + 0xde, 0x0f, 0xf2, 0x44, 0x87, 0x7e, 0xa6, 0x0a, + 0x4c, 0xb0, 0x43, 0x2c, 0xe5, 0x77, 0xc3, 0x1b, + 0xeb, 0x00, 0x9c, 0x5c, 0x2c, 0x49, 0xaa, 0x2e, + 0x4e, 0xad, 0xb2, 0x17, 0xad, 0x8c, 0xc0, 0x9b, + }, + }, + { + /* + * One of the MD5 test vectors, included for the "short + * update" test. + */ + "\"1234567890\"x8", + "1234567890123456789012345678901234567890" + "1234567890123456789012345678901234567890", + { + 0x72, 0xec, 0x1e, 0xf1, 0x12, 0x4a, 0x45, 0xb0, + 0x47, 0xe8, 0xb7, 0xc7, 0x5a, 0x93, 0x21, 0x95, + 0x13, 0x5b, 0xb6, 0x1d, 0xe2, 0x4e, 0xc0, 0xd1, + 0x91, 0x40, 0x42, 0x24, 0x6e, 0x0a, 0xec, 0x3a, + 0x23, 0x54, 0xe0, 0x93, 0xd7, 0x6f, 0x30, 0x48, + 0xb4, 0x56, 0x76, 0x43, 0x46, 0x90, 0x0c, 0xb1, + 0x30, 0xd2, 0xa4, 0xfd, 0x5d, 0xd1, 0x6a, 0xbb, + 0x5e, 0x30, 0xbc, 0xb8, 0x50, 0xde, 0xe8, 0x43, + }, + }, +}; + +/* + * Unit test: compute the SHA512 sum of the specified string and compare it + * to the expected result. + */ +static int +t_sha512_vector(char **desc CRYB_UNUSED, void *arg) +{ + struct t_vector *vector = (struct t_vector *)arg; + uint8_t digest[SHA512_DIGEST_LEN]; + char *msg; + + if (vector->msg) { + t_sha512_complete(vector->msg, strlen(vector->msg), digest); + } else { + /* special case for FIPS test vector 3 */ + if ((msg = malloc(1000000)) == NULL) + err(1, "malloc()"); + memset(msg, 'a', 1000000); + t_sha512_complete(msg, 1000000, digest); + free(msg); + } + if (memcmp(digest, vector->digest, SHA512_DIGEST_LEN) != 0) { + t_verbose("expected "); + t_verbose_hex(vector->digest, SHA512_DIGEST_LEN); + t_verbose("\n"); + t_verbose("got "); + t_verbose_hex(digest, SHA512_DIGEST_LEN); + t_verbose("\n"); + return (0); + } + return (1); +} + + +#if !defined(WITH_OPENSSL) && !defined(WITH_RSAREF) +/* + * Various corner cases and error conditions + */ +static int +t_sha512_short_updates(char **desc CRYB_UNUSED, void *arg) +{ + struct t_vector *vector = (struct t_vector *)arg; + uint8_t digest[SHA512_DIGEST_LEN]; + sha512_ctx ctx; + int i, len; + + sha512_init(&ctx); + len = strlen(vector->msg); + for (i = 0; i + 5 < len; i += 5) + sha512_update(&ctx, vector->msg + i, 5); + sha512_update(&ctx, vector->msg + i, len - i); + sha512_final(&ctx, digest); + return (memcmp(digest, vector->digest, SHA512_DIGEST_LEN) == 0); +} +#endif + +#ifdef BENCHMARKS +/* + * Performance test: measure the time spent computing the SHA512 sum of a + * message of the specified length. + */ +#define T_PERF_ITERATIONS 1000 +static int +t_sha512_perf(char **desc, void *arg) +{ + struct timespec ts, te; + unsigned long ns; + uint8_t digest[SHA512_DIGEST_LEN]; + char *msg, *comment; + size_t msglen = *(size_t *)arg; + + if ((msg = calloc(1, msglen)) == NULL) + err(1, "calloc()"); + clock_gettime(CLOCK_MONOTONIC_PRECISE, &ts); + for (int i = 0; i < T_PERF_ITERATIONS; ++i) + t_sha512_complete(msg, msglen, digest); + clock_gettime(CLOCK_MONOTONIC_PRECISE, &te); + free(msg); + ns = te.tv_sec * 1000000000LU + te.tv_nsec; + ns -= ts.tv_sec * 1000000000LU + ts.tv_nsec; + asprintf(&comment, "%zu bytes: %d iterations in %'lu ns", + msglen, T_PERF_ITERATIONS, ns); + if (comment == NULL) + err(1, "asprintf()"); + *desc = comment; + return (1); +} +#endif + + +/*************************************************************************** + * Boilerplate + */ + +int +t_prepare(int argc, char *argv[]) +{ + int i, n; + + (void)argc; + (void)argv; + n = sizeof t_sha512_vectors / sizeof t_sha512_vectors[0]; + for (i = 0; i < n; ++i) + t_add_test(t_sha512_vector, &t_sha512_vectors[i], + t_sha512_vectors[i].desc); +#if !defined(WITH_OPENSSL) && !defined(WITH_RSAREF) + /* + * Run test vector 5 (md5 test vector 7, which is 80 characters + * long) 5 characters at a time. This tests a) appending data to + * an underfull block and b) appending more data to an underfull + * block than it has room for (since 64 % 5 != 0). Test vector 4 + * and 5 already exercised the code path for computing a block + * directly from source (without copying it in), and all the test + * vectors except vector 1 exercised the general case of copying a + * small amount of data in without crossing the block boundary. + */ + t_add_test(t_sha512_short_updates, &t_sha512_vectors[4], + "multiple short updates"); +#endif +#ifdef BENCHMARKS + static size_t one = 1, thousand = 1000, million = 1000000; + t_add_test(t_sha512_perf, &one, + "performance test (1 byte)"); + t_add_test(t_sha512_perf, &thousand, + "performance test (1,000 bytes)"); + t_add_test(t_sha512_perf, &million, + "performance test (1,000,000 bytes)"); +#endif + return (0); +} + +void +t_cleanup(void) +{ +}