2005-04-17 02:20:36 +04:00
/* SHA-512 code by Jean-Luc Cooke <jlcooke@certainkey.com>
*
* Copyright ( c ) Jean - Luc Cooke < jlcooke @ certainkey . com >
* Copyright ( c ) Andrew McDonald < andrew @ mcdonald . org . uk >
* Copyright ( c ) 2003 Kyle McMartin < kyle @ debian . org >
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation ; either version 2 , or ( at your option ) any
* later version .
*
*/
2008-12-17 08:49:02 +03:00
# include <crypto/internal/hash.h>
2005-04-17 02:20:36 +04:00
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/mm.h>
# include <linux/init.h>
# include <linux/crypto.h>
2005-10-30 13:25:15 +03:00
# include <linux/types.h>
2007-10-09 18:43:13 +04:00
# include <crypto/sha.h>
2008-12-17 08:47:52 +03:00
# include <linux/percpu.h>
2005-04-17 02:20:36 +04:00
# include <asm/byteorder.h>
static inline u64 Ch ( u64 x , u64 y , u64 z )
{
return z ^ ( x & ( y ^ z ) ) ;
}
static inline u64 Maj ( u64 x , u64 y , u64 z )
{
return ( x & y ) | ( z & ( x | y ) ) ;
}
static inline u64 RORu64 ( u64 x , u64 y )
{
return ( x > > y ) | ( x < < ( 64 - y ) ) ;
}
static const u64 sha512_K [ 80 ] = {
0x428a2f98d728ae22ULL , 0x7137449123ef65cdULL , 0xb5c0fbcfec4d3b2fULL ,
0xe9b5dba58189dbbcULL , 0x3956c25bf348b538ULL , 0x59f111f1b605d019ULL ,
0x923f82a4af194f9bULL , 0xab1c5ed5da6d8118ULL , 0xd807aa98a3030242ULL ,
0x12835b0145706fbeULL , 0x243185be4ee4b28cULL , 0x550c7dc3d5ffb4e2ULL ,
0x72be5d74f27b896fULL , 0x80deb1fe3b1696b1ULL , 0x9bdc06a725c71235ULL ,
0xc19bf174cf692694ULL , 0xe49b69c19ef14ad2ULL , 0xefbe4786384f25e3ULL ,
0x0fc19dc68b8cd5b5ULL , 0x240ca1cc77ac9c65ULL , 0x2de92c6f592b0275ULL ,
0x4a7484aa6ea6e483ULL , 0x5cb0a9dcbd41fbd4ULL , 0x76f988da831153b5ULL ,
0x983e5152ee66dfabULL , 0xa831c66d2db43210ULL , 0xb00327c898fb213fULL ,
0xbf597fc7beef0ee4ULL , 0xc6e00bf33da88fc2ULL , 0xd5a79147930aa725ULL ,
0x06ca6351e003826fULL , 0x142929670a0e6e70ULL , 0x27b70a8546d22ffcULL ,
0x2e1b21385c26c926ULL , 0x4d2c6dfc5ac42aedULL , 0x53380d139d95b3dfULL ,
0x650a73548baf63deULL , 0x766a0abb3c77b2a8ULL , 0x81c2c92e47edaee6ULL ,
0x92722c851482353bULL , 0xa2bfe8a14cf10364ULL , 0xa81a664bbc423001ULL ,
0xc24b8b70d0f89791ULL , 0xc76c51a30654be30ULL , 0xd192e819d6ef5218ULL ,
0xd69906245565a910ULL , 0xf40e35855771202aULL , 0x106aa07032bbd1b8ULL ,
0x19a4c116b8d2d0c8ULL , 0x1e376c085141ab53ULL , 0x2748774cdf8eeb99ULL ,
0x34b0bcb5e19b48a8ULL , 0x391c0cb3c5c95a63ULL , 0x4ed8aa4ae3418acbULL ,
0x5b9cca4f7763e373ULL , 0x682e6ff3d6b2b8a3ULL , 0x748f82ee5defb2fcULL ,
0x78a5636f43172f60ULL , 0x84c87814a1f0ab72ULL , 0x8cc702081a6439ecULL ,
0x90befffa23631e28ULL , 0xa4506cebde82bde9ULL , 0xbef9a3f7b2c67915ULL ,
0xc67178f2e372532bULL , 0xca273eceea26619cULL , 0xd186b8c721c0c207ULL ,
0xeada7dd6cde0eb1eULL , 0xf57d4f7fee6ed178ULL , 0x06f067aa72176fbaULL ,
0x0a637dc5a2c898a6ULL , 0x113f9804bef90daeULL , 0x1b710b35131c471bULL ,
0x28db77f523047d84ULL , 0x32caab7b40c72493ULL , 0x3c9ebe0a15c9bebcULL ,
0x431d67c49c100d4cULL , 0x4cc5d4becb3e42b6ULL , 0x597f299cfc657e2aULL ,
0x5fcb6fab3ad6faecULL , 0x6c44198c4a475817ULL ,
} ;
# define e0(x) (RORu64(x,28) ^ RORu64(x,34) ^ RORu64(x,39))
# define e1(x) (RORu64(x,14) ^ RORu64(x,18) ^ RORu64(x,41))
# define s0(x) (RORu64(x, 1) ^ RORu64(x, 8) ^ (x >> 7))
# define s1(x) (RORu64(x,19) ^ RORu64(x,61) ^ (x >> 6))
static inline void LOAD_OP ( int I , u64 * W , const u8 * input )
{
W [ I ] = __be64_to_cpu ( ( ( __be64 * ) ( input ) ) [ I ] ) ;
}
static inline void BLEND_OP ( int I , u64 * W )
{
2012-01-14 22:40:57 +04:00
W [ I % 16 ] + = s1 ( W [ ( I - 2 ) % 16 ] ) + W [ ( I - 7 ) % 16 ] + s0 ( W [ ( I - 15 ) % 16 ] ) ;
2005-04-17 02:20:36 +04:00
}
static void
2008-12-17 08:47:52 +03:00
sha512_transform ( u64 * state , const u8 * input )
2005-04-17 02:20:36 +04:00
{
u64 a , b , c , d , e , f , g , h , t1 , t2 ;
int i ;
2012-01-14 22:40:57 +04:00
u64 W [ 16 ] ;
2005-04-17 02:20:36 +04:00
/* load the input */
for ( i = 0 ; i < 16 ; i + + )
LOAD_OP ( i , W , input ) ;
/* load the state into our registers */
2008-03-06 14:55:38 +03:00
a = state [ 0 ] ; b = state [ 1 ] ; c = state [ 2 ] ; d = state [ 3 ] ;
e = state [ 4 ] ; f = state [ 5 ] ; g = state [ 6 ] ; h = state [ 7 ] ;
2012-01-14 22:40:57 +04:00
# define SHA512_0_15(i, a, b, c, d, e, f, g, h) \
t1 = h + e1 ( e ) + Ch ( e , f , g ) + sha512_K [ i ] + W [ i ] ; \
t2 = e0 ( a ) + Maj ( a , b , c ) ; \
d + = t1 ; \
h = t1 + t2
# define SHA512_16_79(i, a, b, c, d, e, f, g, h) \
BLEND_OP ( i , W ) ; \
t1 = h + e1 ( e ) + Ch ( e , f , g ) + sha512_K [ i ] + W [ ( i ) % 16 ] ; \
t2 = e0 ( a ) + Maj ( a , b , c ) ; \
d + = t1 ; \
h = t1 + t2
for ( i = 0 ; i < 16 ; i + = 8 ) {
SHA512_0_15 ( i , a , b , c , d , e , f , g , h ) ;
SHA512_0_15 ( i + 1 , h , a , b , c , d , e , f , g ) ;
SHA512_0_15 ( i + 2 , g , h , a , b , c , d , e , f ) ;
SHA512_0_15 ( i + 3 , f , g , h , a , b , c , d , e ) ;
SHA512_0_15 ( i + 4 , e , f , g , h , a , b , c , d ) ;
SHA512_0_15 ( i + 5 , d , e , f , g , h , a , b , c ) ;
SHA512_0_15 ( i + 6 , c , d , e , f , g , h , a , b ) ;
SHA512_0_15 ( i + 7 , b , c , d , e , f , g , h , a ) ;
}
for ( i = 16 ; i < 80 ; i + = 8 ) {
SHA512_16_79 ( i , a , b , c , d , e , f , g , h ) ;
SHA512_16_79 ( i + 1 , h , a , b , c , d , e , f , g ) ;
SHA512_16_79 ( i + 2 , g , h , a , b , c , d , e , f ) ;
SHA512_16_79 ( i + 3 , f , g , h , a , b , c , d , e ) ;
SHA512_16_79 ( i + 4 , e , f , g , h , a , b , c , d ) ;
SHA512_16_79 ( i + 5 , d , e , f , g , h , a , b , c ) ;
SHA512_16_79 ( i + 6 , c , d , e , f , g , h , a , b ) ;
SHA512_16_79 ( i + 7 , b , c , d , e , f , g , h , a ) ;
2005-04-17 02:20:36 +04:00
}
2008-03-06 14:55:38 +03:00
state [ 0 ] + = a ; state [ 1 ] + = b ; state [ 2 ] + = c ; state [ 3 ] + = d ;
state [ 4 ] + = e ; state [ 5 ] + = f ; state [ 6 ] + = g ; state [ 7 ] + = h ;
2005-04-17 02:20:36 +04:00
/* erase our data */
a = b = c = d = e = f = g = h = t1 = t2 = 0 ;
}
2008-12-17 08:49:02 +03:00
static int
sha512_init ( struct shash_desc * desc )
2005-04-17 02:20:36 +04:00
{
2009-07-22 07:48:18 +04:00
struct sha512_state * sctx = shash_desc_ctx ( desc ) ;
2007-10-09 18:43:13 +04:00
sctx - > state [ 0 ] = SHA512_H0 ;
sctx - > state [ 1 ] = SHA512_H1 ;
sctx - > state [ 2 ] = SHA512_H2 ;
sctx - > state [ 3 ] = SHA512_H3 ;
sctx - > state [ 4 ] = SHA512_H4 ;
sctx - > state [ 5 ] = SHA512_H5 ;
sctx - > state [ 6 ] = SHA512_H6 ;
sctx - > state [ 7 ] = SHA512_H7 ;
2009-07-22 08:22:43 +04:00
sctx - > count [ 0 ] = sctx - > count [ 1 ] = 0 ;
2008-12-17 08:49:02 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2008-12-17 08:49:02 +03:00
static int
sha384_init ( struct shash_desc * desc )
2005-04-17 02:20:36 +04:00
{
2009-07-22 07:48:18 +04:00
struct sha512_state * sctx = shash_desc_ctx ( desc ) ;
2007-10-09 18:43:13 +04:00
sctx - > state [ 0 ] = SHA384_H0 ;
sctx - > state [ 1 ] = SHA384_H1 ;
sctx - > state [ 2 ] = SHA384_H2 ;
sctx - > state [ 3 ] = SHA384_H3 ;
sctx - > state [ 4 ] = SHA384_H4 ;
sctx - > state [ 5 ] = SHA384_H5 ;
sctx - > state [ 6 ] = SHA384_H6 ;
sctx - > state [ 7 ] = SHA384_H7 ;
2009-07-22 08:22:43 +04:00
sctx - > count [ 0 ] = sctx - > count [ 1 ] = 0 ;
2008-12-17 08:49:02 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2008-12-17 08:49:02 +03:00
static int
sha512_update ( struct shash_desc * desc , const u8 * data , unsigned int len )
2005-04-17 02:20:36 +04:00
{
2009-07-22 07:48:18 +04:00
struct sha512_state * sctx = shash_desc_ctx ( desc ) ;
2005-04-17 02:20:36 +04:00
unsigned int i , index , part_len ;
/* Compute number of bytes mod 128 */
2009-07-22 08:22:43 +04:00
index = sctx - > count [ 0 ] & 0x7f ;
/* Update number of bytes */
if ( ! ( sctx - > count [ 0 ] + = len ) )
sctx - > count [ 1 ] + + ;
2008-03-06 14:55:38 +03:00
2005-04-17 02:20:36 +04:00
part_len = 128 - index ;
2008-03-06 14:55:38 +03:00
2005-04-17 02:20:36 +04:00
/* Transform as many times as possible. */
if ( len > = part_len ) {
memcpy ( & sctx - > buf [ index ] , data , part_len ) ;
2008-12-17 08:47:52 +03:00
sha512_transform ( sctx - > state , sctx - > buf ) ;
2005-04-17 02:20:36 +04:00
for ( i = part_len ; i + 127 < len ; i + = 128 )
2008-12-17 08:47:52 +03:00
sha512_transform ( sctx - > state , & data [ i ] ) ;
2005-04-17 02:20:36 +04:00
index = 0 ;
} else {
i = 0 ;
}
/* Buffer remaining input */
memcpy ( & sctx - > buf [ index ] , & data [ i ] , len - i ) ;
2008-12-17 08:49:02 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2008-12-17 08:49:02 +03:00
static int
sha512_final ( struct shash_desc * desc , u8 * hash )
2005-04-17 02:20:36 +04:00
{
2009-07-22 07:48:18 +04:00
struct sha512_state * sctx = shash_desc_ctx ( desc ) ;
2005-04-17 02:20:36 +04:00
static u8 padding [ 128 ] = { 0x80 , } ;
2005-10-30 13:25:15 +03:00
__be64 * dst = ( __be64 * ) hash ;
2009-07-22 08:22:43 +04:00
__be64 bits [ 2 ] ;
2005-04-17 02:20:36 +04:00
unsigned int index , pad_len ;
2005-10-30 13:25:15 +03:00
int i ;
2005-04-17 02:20:36 +04:00
/* Save number of bits */
2009-07-22 08:22:43 +04:00
bits [ 1 ] = cpu_to_be64 ( sctx - > count [ 0 ] < < 3 ) ;
bits [ 0 ] = cpu_to_be64 ( sctx - > count [ 1 ] < < 3 | sctx - > count [ 0 ] > > 61 ) ;
2005-04-17 02:20:36 +04:00
/* Pad out to 112 mod 128. */
2009-07-22 08:22:43 +04:00
index = sctx - > count [ 0 ] & 0x7f ;
2005-04-17 02:20:36 +04:00
pad_len = ( index < 112 ) ? ( 112 - index ) : ( ( 128 + 112 ) - index ) ;
2008-12-17 08:49:02 +03:00
sha512_update ( desc , padding , pad_len ) ;
2005-04-17 02:20:36 +04:00
/* Append length (before padding) */
2008-12-17 08:49:02 +03:00
sha512_update ( desc , ( const u8 * ) bits , sizeof ( bits ) ) ;
2005-04-17 02:20:36 +04:00
/* Store state in digest */
2005-10-30 13:25:15 +03:00
for ( i = 0 ; i < 8 ; i + + )
dst [ i ] = cpu_to_be64 ( sctx - > state [ i ] ) ;
2005-04-17 02:20:36 +04:00
/* Zeroize sensitive information. */
2009-07-22 07:48:18 +04:00
memset ( sctx , 0 , sizeof ( struct sha512_state ) ) ;
2008-12-17 08:49:02 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2008-12-17 08:49:02 +03:00
static int sha384_final ( struct shash_desc * desc , u8 * hash )
2005-04-17 02:20:36 +04:00
{
2008-12-17 08:49:02 +03:00
u8 D [ 64 ] ;
2005-04-17 02:20:36 +04:00
2008-12-17 08:49:02 +03:00
sha512_final ( desc , D ) ;
2005-04-17 02:20:36 +04:00
2008-12-17 08:49:02 +03:00
memcpy ( hash , D , 48 ) ;
memset ( D , 0 , 64 ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
2008-12-17 08:49:02 +03:00
static struct shash_alg sha512 = {
. digestsize = SHA512_DIGEST_SIZE ,
. init = sha512_init ,
. update = sha512_update ,
. final = sha512_final ,
2009-07-22 07:48:18 +04:00
. descsize = sizeof ( struct sha512_state ) ,
2008-12-17 08:49:02 +03:00
. base = {
. cra_name = " sha512 " ,
. cra_flags = CRYPTO_ALG_TYPE_SHASH ,
. cra_blocksize = SHA512_BLOCK_SIZE ,
. cra_module = THIS_MODULE ,
}
2005-04-17 02:20:36 +04:00
} ;
2008-12-17 08:49:02 +03:00
static struct shash_alg sha384 = {
. digestsize = SHA384_DIGEST_SIZE ,
. init = sha384_init ,
. update = sha512_update ,
. final = sha384_final ,
2009-07-22 07:48:18 +04:00
. descsize = sizeof ( struct sha512_state ) ,
2008-12-17 08:49:02 +03:00
. base = {
. cra_name = " sha384 " ,
. cra_flags = CRYPTO_ALG_TYPE_SHASH ,
. cra_blocksize = SHA384_BLOCK_SIZE ,
. cra_module = THIS_MODULE ,
}
2005-04-17 02:20:36 +04:00
} ;
2008-04-05 17:00:57 +04:00
static int __init sha512_generic_mod_init ( void )
2005-04-17 02:20:36 +04:00
{
int ret = 0 ;
2008-12-17 08:49:02 +03:00
if ( ( ret = crypto_register_shash ( & sha384 ) ) < 0 )
2005-04-17 02:20:36 +04:00
goto out ;
2008-12-17 08:49:02 +03:00
if ( ( ret = crypto_register_shash ( & sha512 ) ) < 0 )
crypto_unregister_shash ( & sha384 ) ;
2005-04-17 02:20:36 +04:00
out :
return ret ;
}
2008-04-05 17:00:57 +04:00
static void __exit sha512_generic_mod_fini ( void )
2005-04-17 02:20:36 +04:00
{
2008-12-17 08:49:02 +03:00
crypto_unregister_shash ( & sha384 ) ;
crypto_unregister_shash ( & sha512 ) ;
2005-04-17 02:20:36 +04:00
}
2008-04-05 17:00:57 +04:00
module_init ( sha512_generic_mod_init ) ;
module_exit ( sha512_generic_mod_fini ) ;
2005-04-17 02:20:36 +04:00
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( " SHA-512 and SHA-384 Secure Hash Algorithms " ) ;
2008-03-06 14:55:38 +03:00
MODULE_ALIAS ( " sha384 " ) ;
MODULE_ALIAS ( " sha512 " ) ;