iPXE
sha512.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2015 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301, USA.
00018  *
00019  * You can also choose to distribute this program under the terms of
00020  * the Unmodified Binary Distribution Licence (as given in the file
00021  * COPYING.UBDL), provided that you have satisfied its requirements.
00022  */
00023 
00024 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00025 
00026 /** @file
00027  *
00028  * SHA-512 algorithm
00029  *
00030  */
00031 
00032 #include <stdint.h>
00033 #include <string.h>
00034 #include <byteswap.h>
00035 #include <assert.h>
00036 #include <ipxe/rotate.h>
00037 #include <ipxe/crypto.h>
00038 #include <ipxe/asn1.h>
00039 #include <ipxe/sha512.h>
00040 
00041 /** SHA-512 variables */
00042 struct sha512_variables {
00043         /* This layout matches that of struct sha512_digest_data,
00044          * allowing for efficient endianness-conversion,
00045          */
00046         uint64_t a;
00047         uint64_t b;
00048         uint64_t c;
00049         uint64_t d;
00050         uint64_t e;
00051         uint64_t f;
00052         uint64_t g;
00053         uint64_t h;
00054         uint64_t w[SHA512_ROUNDS];
00055 } __attribute__ (( packed ));
00056 
00057 /** SHA-512 constants */
00058 static const uint64_t k[SHA512_ROUNDS] = {
00059         0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL,
00060         0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
00061         0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL,
00062         0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
00063         0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL,
00064         0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
00065         0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL,
00066         0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
00067         0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL,
00068         0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
00069         0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL,
00070         0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
00071         0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL,
00072         0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
00073         0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL,
00074         0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
00075         0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL,
00076         0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
00077         0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL,
00078         0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
00079         0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL,
00080         0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
00081         0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL,
00082         0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
00083         0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL,
00084         0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
00085         0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
00086 };
00087 
00088 /** SHA-512 initial digest values */
00089 static const struct sha512_digest sha512_init_digest = {
00090         .h = {
00091                 cpu_to_be64 ( 0x6a09e667f3bcc908ULL ),
00092                 cpu_to_be64 ( 0xbb67ae8584caa73bULL ),
00093                 cpu_to_be64 ( 0x3c6ef372fe94f82bULL ),
00094                 cpu_to_be64 ( 0xa54ff53a5f1d36f1ULL ),
00095                 cpu_to_be64 ( 0x510e527fade682d1ULL ),
00096                 cpu_to_be64 ( 0x9b05688c2b3e6c1fULL ),
00097                 cpu_to_be64 ( 0x1f83d9abfb41bd6bULL ),
00098                 cpu_to_be64 ( 0x5be0cd19137e2179ULL ),
00099         },
00100 };
00101 
00102 /**
00103  * Initialise SHA-512 family algorithm
00104  *
00105  * @v context           SHA-512 context
00106  * @v init              Initial digest values
00107  * @v digestsize        Digest size
00108  */
00109 void sha512_family_init ( struct sha512_context *context,
00110                           const struct sha512_digest *init,
00111                           size_t digestsize ) {
00112 
00113         context->len = 0;
00114         context->digestsize = digestsize;
00115         memcpy ( &context->ddq.dd.digest, init,
00116                  sizeof ( context->ddq.dd.digest ) );
00117 }
00118 
00119 /**
00120  * Initialise SHA-512 algorithm
00121  *
00122  * @v ctx               SHA-512 context
00123  */
00124 static void sha512_init ( void *ctx ) {
00125         struct sha512_context *context = ctx;
00126 
00127         sha512_family_init ( context, &sha512_init_digest,
00128                              sizeof ( struct sha512_digest ) );
00129 }
00130 
00131 /**
00132  * Calculate SHA-512 digest of accumulated data
00133  *
00134  * @v context           SHA-512 context
00135  */
00136 static void sha512_digest ( struct sha512_context *context ) {
00137         union {
00138                 union sha512_digest_data_qwords ddq;
00139                 struct sha512_variables v;
00140         } u;
00141         uint64_t *a = &u.v.a;
00142         uint64_t *b = &u.v.b;
00143         uint64_t *c = &u.v.c;
00144         uint64_t *d = &u.v.d;
00145         uint64_t *e = &u.v.e;
00146         uint64_t *f = &u.v.f;
00147         uint64_t *g = &u.v.g;
00148         uint64_t *h = &u.v.h;
00149         uint64_t *w = u.v.w;
00150         uint64_t s0;
00151         uint64_t s1;
00152         uint64_t maj;
00153         uint64_t t1;
00154         uint64_t t2;
00155         uint64_t ch;
00156         unsigned int i;
00157 
00158         /* Sanity checks */
00159         assert ( ( context->len % sizeof ( context->ddq.dd.data ) ) == 0 );
00160         linker_assert ( &u.ddq.dd.digest.h[0] == a, sha512_bad_layout );
00161         linker_assert ( &u.ddq.dd.digest.h[1] == b, sha512_bad_layout );
00162         linker_assert ( &u.ddq.dd.digest.h[2] == c, sha512_bad_layout );
00163         linker_assert ( &u.ddq.dd.digest.h[3] == d, sha512_bad_layout );
00164         linker_assert ( &u.ddq.dd.digest.h[4] == e, sha512_bad_layout );
00165         linker_assert ( &u.ddq.dd.digest.h[5] == f, sha512_bad_layout );
00166         linker_assert ( &u.ddq.dd.digest.h[6] == g, sha512_bad_layout );
00167         linker_assert ( &u.ddq.dd.digest.h[7] == h, sha512_bad_layout );
00168         linker_assert ( &u.ddq.dd.data.qword[0] == w, sha512_bad_layout );
00169 
00170         DBGC ( context, "SHA512 digesting:\n" );
00171         DBGC_HDA ( context, 0, &context->ddq.dd.digest,
00172                    sizeof ( context->ddq.dd.digest ) );
00173         DBGC_HDA ( context, context->len, &context->ddq.dd.data,
00174                    sizeof ( context->ddq.dd.data ) );
00175 
00176         /* Convert h[0..7] to host-endian, and initialise a, b, c, d,
00177          * e, f, g, h, and w[0..15]
00178          */
00179         for ( i = 0 ; i < ( sizeof ( u.ddq.qword ) /
00180                             sizeof ( u.ddq.qword[0] ) ) ; i++ ) {
00181                 be64_to_cpus ( &context->ddq.qword[i] );
00182                 u.ddq.qword[i] = context->ddq.qword[i];
00183         }
00184 
00185         /* Initialise w[16..79] */
00186         for ( i = 16 ; i < SHA512_ROUNDS ; i++ ) {
00187                 s0 = ( ror64 ( w[i-15], 1 ) ^ ror64 ( w[i-15], 8 ) ^
00188                        ( w[i-15] >> 7 ) );
00189                 s1 = ( ror64 ( w[i-2], 19 ) ^ ror64 ( w[i-2], 61 ) ^
00190                        ( w[i-2] >> 6 ) );
00191                 w[i] = ( w[i-16] + s0 + w[i-7] + s1 );
00192         }
00193 
00194         /* Main loop */
00195         for ( i = 0 ; i < SHA512_ROUNDS ; i++ ) {
00196                 s0 = ( ror64 ( *a, 28 ) ^ ror64 ( *a, 34 ) ^ ror64 ( *a, 39 ) );
00197                 maj = ( ( *a & *b ) ^ ( *a & *c ) ^ ( *b & *c ) );
00198                 t2 = ( s0 + maj );
00199                 s1 = ( ror64 ( *e, 14 ) ^ ror64 ( *e, 18 ) ^ ror64 ( *e, 41 ) );
00200                 ch = ( ( *e & *f ) ^ ( (~*e) & *g ) );
00201                 t1 = ( *h + s1 + ch + k[i] + w[i] );
00202                 *h = *g;
00203                 *g = *f;
00204                 *f = *e;
00205                 *e = ( *d + t1 );
00206                 *d = *c;
00207                 *c = *b;
00208                 *b = *a;
00209                 *a = ( t1 + t2 );
00210                 DBGC2 ( context, "%2d : %016llx %016llx %016llx %016llx "
00211                         "%016llx %016llx %016llx %016llx\n",
00212                         i, *a, *b, *c, *d, *e, *f, *g, *h );
00213         }
00214 
00215         /* Add chunk to hash and convert back to big-endian */
00216         for ( i = 0 ; i < 8 ; i++ ) {
00217                 context->ddq.dd.digest.h[i] =
00218                         cpu_to_be64 ( context->ddq.dd.digest.h[i] +
00219                                       u.ddq.dd.digest.h[i] );
00220         }
00221 
00222         DBGC ( context, "SHA512 digested:\n" );
00223         DBGC_HDA ( context, 0, &context->ddq.dd.digest,
00224                    sizeof ( context->ddq.dd.digest ) );
00225 }
00226 
00227 /**
00228  * Accumulate data with SHA-512 algorithm
00229  *
00230  * @v ctx               SHA-512 context
00231  * @v data              Data
00232  * @v len               Length of data
00233  */
00234 void sha512_update ( void *ctx, const void *data, size_t len ) {
00235         struct sha512_context *context = ctx;
00236         const uint8_t *byte = data;
00237         size_t offset;
00238 
00239         /* Accumulate data a byte at a time, performing the digest
00240          * whenever we fill the data buffer
00241          */
00242         while ( len-- ) {
00243                 offset = ( context->len % sizeof ( context->ddq.dd.data ) );
00244                 context->ddq.dd.data.byte[offset] = *(byte++);
00245                 context->len++;
00246                 if ( ( context->len % sizeof ( context->ddq.dd.data ) ) == 0 )
00247                         sha512_digest ( context );
00248         }
00249 }
00250 
00251 /**
00252  * Generate SHA-512 digest
00253  *
00254  * @v ctx               SHA-512 context
00255  * @v out               Output buffer
00256  */
00257 void sha512_final ( void *ctx, void *out ) {
00258         struct sha512_context *context = ctx;
00259         uint64_t len_bits_hi;
00260         uint64_t len_bits_lo;
00261         uint8_t pad;
00262 
00263         /* Record length before pre-processing */
00264         len_bits_hi = 0;
00265         len_bits_lo = cpu_to_be64 ( ( ( uint64_t ) context->len ) * 8 );
00266 
00267         /* Pad with a single "1" bit followed by as many "0" bits as required */
00268         pad = 0x80;
00269         do {
00270                 sha512_update ( ctx, &pad, sizeof ( pad ) );
00271                 pad = 0x00;
00272         } while ( ( context->len % sizeof ( context->ddq.dd.data ) ) !=
00273                   offsetof ( typeof ( context->ddq.dd.data ), final.len_hi ) );
00274 
00275         /* Append length (in bits) */
00276         sha512_update ( ctx, &len_bits_hi, sizeof ( len_bits_hi ) );
00277         sha512_update ( ctx, &len_bits_lo, sizeof ( len_bits_lo ) );
00278         assert ( ( context->len % sizeof ( context->ddq.dd.data ) ) == 0 );
00279 
00280         /* Copy out final digest */
00281         memcpy ( out, &context->ddq.dd.digest, context->digestsize );
00282 }
00283 
00284 /** SHA-512 algorithm */
00285 struct digest_algorithm sha512_algorithm = {
00286         .name           = "sha512",
00287         .ctxsize        = sizeof ( struct sha512_context ),
00288         .blocksize      = sizeof ( union sha512_block ),
00289         .digestsize     = sizeof ( struct sha512_digest ),
00290         .init           = sha512_init,
00291         .update         = sha512_update,
00292         .final          = sha512_final,
00293 };
00294 
00295 /** "sha512" object identifier */
00296 static uint8_t oid_sha512[] = { ASN1_OID_SHA512 };
00297 
00298 /** "sha512" OID-identified algorithm */
00299 struct asn1_algorithm oid_sha512_algorithm __asn1_algorithm = {
00300         .name = "sha512",
00301         .digest = &sha512_algorithm,
00302         .oid = ASN1_OID_CURSOR ( oid_sha512 ),
00303 };