1 /* 2 * Cryptographic API. 3 * 4 * s390 implementation of the SHA1 Secure Hash Algorithm. 5 * 6 * Derived from cryptoapi implementation, adapted for in-place 7 * scatterlist interface. Originally based on the public domain 8 * implementation written by Steve Reid. 9 * 10 * s390 Version: 11 * Copyright (C) 2003 IBM Deutschland GmbH, IBM Corporation 12 * Author(s): Thomas Spatzier (tspat@de.ibm.com) 13 * 14 * Derived from "crypto/sha1.c" 15 * Copyright (c) Alan Smithee. 16 * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk> 17 * Copyright (c) Jean-Francois Dive <jef@linuxbe.org> 18 * 19 * This program is free software; you can redistribute it and/or modify it 20 * under the terms of the GNU General Public License as published by the Free 21 * Software Foundation; either version 2 of the License, or (at your option) 22 * any later version. 23 * 24 */ 25 #include <linux/init.h> 26 #include <linux/module.h> 27 #include <linux/mm.h> 28 #include <linux/crypto.h> 29 #include <asm/scatterlist.h> 30 #include <asm/byteorder.h> 31 #include "crypt_s390.h" 32 33 #define SHA1_DIGEST_SIZE 20 34 #define SHA1_BLOCK_SIZE 64 35 36 struct crypt_s390_sha1_ctx { 37 u64 count; 38 u32 state[5]; 39 u32 buf_len; 40 u8 buffer[2 * SHA1_BLOCK_SIZE]; 41 }; 42 43 static void sha1_init(struct crypto_tfm *tfm) 44 { 45 struct crypt_s390_sha1_ctx *ctx = crypto_tfm_ctx(tfm); 46 static const u32 initstate[5] = { 47 0x67452301, 48 0xEFCDAB89, 49 0x98BADCFE, 50 0x10325476, 51 0xC3D2E1F0 52 }; 53 54 ctx->count = 0; 55 memcpy(ctx->state, &initstate, sizeof(initstate)); 56 ctx->buf_len = 0; 57 } 58 59 static void sha1_update(struct crypto_tfm *tfm, const u8 *data, 60 unsigned int len) 61 { 62 struct crypt_s390_sha1_ctx *sctx; 63 long imd_len; 64 65 sctx = crypto_tfm_ctx(tfm); 66 sctx->count += len * 8; //message bit length 67 68 //anything in buffer yet? -> must be completed 69 if (sctx->buf_len && (sctx->buf_len + len) >= SHA1_BLOCK_SIZE) { 70 //complete full block and hash 71 memcpy(sctx->buffer + sctx->buf_len, data, 72 SHA1_BLOCK_SIZE - sctx->buf_len); 73 crypt_s390_kimd(KIMD_SHA_1, sctx->state, sctx->buffer, 74 SHA1_BLOCK_SIZE); 75 data += SHA1_BLOCK_SIZE - sctx->buf_len; 76 len -= SHA1_BLOCK_SIZE - sctx->buf_len; 77 sctx->buf_len = 0; 78 } 79 80 //rest of data contains full blocks? 81 imd_len = len & ~0x3ful; 82 if (imd_len){ 83 crypt_s390_kimd(KIMD_SHA_1, sctx->state, data, imd_len); 84 data += imd_len; 85 len -= imd_len; 86 } 87 //anything left? store in buffer 88 if (len){ 89 memcpy(sctx->buffer + sctx->buf_len , data, len); 90 sctx->buf_len += len; 91 } 92 } 93 94 95 static void 96 pad_message(struct crypt_s390_sha1_ctx* sctx) 97 { 98 int index; 99 100 index = sctx->buf_len; 101 sctx->buf_len = (sctx->buf_len < 56)? 102 SHA1_BLOCK_SIZE:2 * SHA1_BLOCK_SIZE; 103 //start pad with 1 104 sctx->buffer[index] = 0x80; 105 //pad with zeros 106 index++; 107 memset(sctx->buffer + index, 0x00, sctx->buf_len - index); 108 //append length 109 memcpy(sctx->buffer + sctx->buf_len - 8, &sctx->count, 110 sizeof sctx->count); 111 } 112 113 /* Add padding and return the message digest. */ 114 static void sha1_final(struct crypto_tfm *tfm, u8 *out) 115 { 116 struct crypt_s390_sha1_ctx *sctx = crypto_tfm_ctx(tfm); 117 118 //must perform manual padding 119 pad_message(sctx); 120 crypt_s390_kimd(KIMD_SHA_1, sctx->state, sctx->buffer, sctx->buf_len); 121 //copy digest to out 122 memcpy(out, sctx->state, SHA1_DIGEST_SIZE); 123 /* Wipe context */ 124 memset(sctx, 0, sizeof *sctx); 125 } 126 127 static struct crypto_alg alg = { 128 .cra_name = "sha1", 129 .cra_driver_name = "sha1-s390", 130 .cra_priority = CRYPT_S390_PRIORITY, 131 .cra_flags = CRYPTO_ALG_TYPE_DIGEST, 132 .cra_blocksize = SHA1_BLOCK_SIZE, 133 .cra_ctxsize = sizeof(struct crypt_s390_sha1_ctx), 134 .cra_module = THIS_MODULE, 135 .cra_list = LIST_HEAD_INIT(alg.cra_list), 136 .cra_u = { .digest = { 137 .dia_digestsize = SHA1_DIGEST_SIZE, 138 .dia_init = sha1_init, 139 .dia_update = sha1_update, 140 .dia_final = sha1_final } } 141 }; 142 143 static int 144 init(void) 145 { 146 int ret = -ENOSYS; 147 148 if (crypt_s390_func_available(KIMD_SHA_1)){ 149 ret = crypto_register_alg(&alg); 150 if (ret == 0){ 151 printk(KERN_INFO "crypt_s390: sha1_s390 loaded.\n"); 152 } 153 } 154 return ret; 155 } 156 157 static void __exit 158 fini(void) 159 { 160 crypto_unregister_alg(&alg); 161 } 162 163 module_init(init); 164 module_exit(fini); 165 166 MODULE_ALIAS("sha1"); 167 168 MODULE_LICENSE("GPL"); 169 MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm"); 170