Loading drivers/crypto/atmel-sha-regs.h +4 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ #define SHA_MR_ALGO_SHA384 (2 << 8) #define SHA_MR_ALGO_SHA512 (3 << 8) #define SHA_MR_ALGO_SHA224 (4 << 8) #define SHA_MR_HMAC (1 << 11) #define SHA_MR_DUALBUFF (1 << 16) #define SHA_IER 0x10 Loading @@ -42,6 +43,9 @@ #define SHA_ISR_URAT_MR (0x2 << 12) #define SHA_ISR_URAT_WO (0x5 << 12) #define SHA_MSR 0x20 #define SHA_BCR 0x30 #define SHA_HW_VERSION 0xFC #define SHA_TPR 0x108 Loading drivers/crypto/atmel-sha.c +597 −1 Original line number Diff line number Diff line Loading @@ -51,13 +51,20 @@ #define SHA_FLAGS_CPU BIT(5) #define SHA_FLAGS_DMA_READY BIT(6) /* bits[10:8] are reserved. */ /* bits[11:8] are reserved. */ #define SHA_FLAGS_ALGO_MASK SHA_MR_ALGO_MASK #define SHA_FLAGS_SHA1 SHA_MR_ALGO_SHA1 #define SHA_FLAGS_SHA256 SHA_MR_ALGO_SHA256 #define SHA_FLAGS_SHA384 SHA_MR_ALGO_SHA384 #define SHA_FLAGS_SHA512 SHA_MR_ALGO_SHA512 #define SHA_FLAGS_SHA224 SHA_MR_ALGO_SHA224 #define SHA_FLAGS_HMAC SHA_MR_HMAC #define SHA_FLAGS_HMAC_SHA1 (SHA_FLAGS_HMAC | SHA_FLAGS_SHA1) #define SHA_FLAGS_HMAC_SHA256 (SHA_FLAGS_HMAC | SHA_FLAGS_SHA256) #define SHA_FLAGS_HMAC_SHA384 (SHA_FLAGS_HMAC | SHA_FLAGS_SHA384) #define SHA_FLAGS_HMAC_SHA512 (SHA_FLAGS_HMAC | SHA_FLAGS_SHA512) #define SHA_FLAGS_HMAC_SHA224 (SHA_FLAGS_HMAC | SHA_FLAGS_SHA224) #define SHA_FLAGS_MODE_MASK (SHA_FLAGS_HMAC | SHA_FLAGS_ALGO_MASK) #define SHA_FLAGS_FINUP BIT(16) #define SHA_FLAGS_SG BIT(17) Loading @@ -67,8 +74,10 @@ #define SHA_FLAGS_IDATAR0 BIT(26) #define SHA_FLAGS_WAIT_DATARDY BIT(27) #define SHA_OP_INIT 0 #define SHA_OP_UPDATE 1 #define SHA_OP_FINAL 2 #define SHA_OP_DIGEST 3 #define SHA_BUFFER_LEN (PAGE_SIZE / 16) Loading @@ -80,6 +89,7 @@ struct atmel_sha_caps { bool has_sha224; bool has_sha_384_512; bool has_uihv; bool has_hmac; }; struct atmel_sha_dev; Loading @@ -105,6 +115,7 @@ struct atmel_sha_reqctx { unsigned int total; /* total request */ size_t block_size; size_t hash_size; u8 buffer[SHA_BUFFER_LEN + SHA512_BLOCK_SIZE] __aligned(sizeof(u32)); }; Loading Loading @@ -152,6 +163,8 @@ struct atmel_sha_dev { struct atmel_sha_caps caps; struct scatterlist tmp; u32 hw_version; }; Loading Loading @@ -1522,11 +1535,579 @@ static int atmel_sha_cpu_start(struct atmel_sha_dev *dd, return atmel_sha_cpu_transfer(dd); } static int atmel_sha_cpu_hash(struct atmel_sha_dev *dd, const void *data, unsigned int datalen, bool auto_padding, atmel_sha_fn_t resume) { struct ahash_request *req = dd->req; struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); u32 msglen = (auto_padding) ? datalen : 0; u32 mr = SHA_MR_MODE_AUTO; if (!(IS_ALIGNED(datalen, ctx->block_size) || auto_padding)) return atmel_sha_complete(dd, -EINVAL); mr |= (ctx->flags & SHA_FLAGS_ALGO_MASK); atmel_sha_write(dd, SHA_MR, mr); atmel_sha_write(dd, SHA_MSR, msglen); atmel_sha_write(dd, SHA_BCR, msglen); atmel_sha_write(dd, SHA_CR, SHA_CR_FIRST); sg_init_one(&dd->tmp, data, datalen); return atmel_sha_cpu_start(dd, &dd->tmp, datalen, false, true, resume); } /* hmac functions */ struct atmel_sha_hmac_key { bool valid; unsigned int keylen; u8 buffer[SHA512_BLOCK_SIZE]; u8 *keydup; }; static inline void atmel_sha_hmac_key_init(struct atmel_sha_hmac_key *hkey) { memset(hkey, 0, sizeof(*hkey)); } static inline void atmel_sha_hmac_key_release(struct atmel_sha_hmac_key *hkey) { kfree(hkey->keydup); memset(hkey, 0, sizeof(*hkey)); } static inline int atmel_sha_hmac_key_set(struct atmel_sha_hmac_key *hkey, const u8 *key, unsigned int keylen) { atmel_sha_hmac_key_release(hkey); if (keylen > sizeof(hkey->buffer)) { hkey->keydup = kmemdup(key, keylen, GFP_KERNEL); if (!hkey->keydup) return -ENOMEM; } else { memcpy(hkey->buffer, key, keylen); } hkey->valid = true; hkey->keylen = keylen; return 0; } static inline bool atmel_sha_hmac_key_get(const struct atmel_sha_hmac_key *hkey, const u8 **key, unsigned int *keylen) { if (!hkey->valid) return false; *keylen = hkey->keylen; *key = (hkey->keydup) ? hkey->keydup : hkey->buffer; return true; } struct atmel_sha_hmac_ctx { struct atmel_sha_ctx base; struct atmel_sha_hmac_key hkey; u32 ipad[SHA512_BLOCK_SIZE / sizeof(u32)]; u32 opad[SHA512_BLOCK_SIZE / sizeof(u32)]; atmel_sha_fn_t resume; }; static int atmel_sha_hmac_setup(struct atmel_sha_dev *dd, atmel_sha_fn_t resume); static int atmel_sha_hmac_prehash_key(struct atmel_sha_dev *dd, const u8 *key, unsigned int keylen); static int atmel_sha_hmac_prehash_key_done(struct atmel_sha_dev *dd); static int atmel_sha_hmac_compute_ipad_hash(struct atmel_sha_dev *dd); static int atmel_sha_hmac_compute_opad_hash(struct atmel_sha_dev *dd); static int atmel_sha_hmac_setup_done(struct atmel_sha_dev *dd); static int atmel_sha_hmac_init_done(struct atmel_sha_dev *dd); static int atmel_sha_hmac_final(struct atmel_sha_dev *dd); static int atmel_sha_hmac_final_done(struct atmel_sha_dev *dd); static int atmel_sha_hmac_digest2(struct atmel_sha_dev *dd); static int atmel_sha_hmac_setup(struct atmel_sha_dev *dd, atmel_sha_fn_t resume) { struct ahash_request *req = dd->req; struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm); unsigned int keylen; const u8 *key; size_t bs; hmac->resume = resume; switch (ctx->flags & SHA_FLAGS_ALGO_MASK) { case SHA_FLAGS_SHA1: ctx->block_size = SHA1_BLOCK_SIZE; ctx->hash_size = SHA1_DIGEST_SIZE; break; case SHA_FLAGS_SHA224: ctx->block_size = SHA224_BLOCK_SIZE; ctx->hash_size = SHA256_DIGEST_SIZE; break; case SHA_FLAGS_SHA256: ctx->block_size = SHA256_BLOCK_SIZE; ctx->hash_size = SHA256_DIGEST_SIZE; break; case SHA_FLAGS_SHA384: ctx->block_size = SHA384_BLOCK_SIZE; ctx->hash_size = SHA512_DIGEST_SIZE; break; case SHA_FLAGS_SHA512: ctx->block_size = SHA512_BLOCK_SIZE; ctx->hash_size = SHA512_DIGEST_SIZE; break; default: return atmel_sha_complete(dd, -EINVAL); } bs = ctx->block_size; if (likely(!atmel_sha_hmac_key_get(&hmac->hkey, &key, &keylen))) return resume(dd); /* Compute K' from K. */ if (unlikely(keylen > bs)) return atmel_sha_hmac_prehash_key(dd, key, keylen); /* Prepare ipad. */ memcpy((u8 *)hmac->ipad, key, keylen); memset((u8 *)hmac->ipad + keylen, 0, bs - keylen); return atmel_sha_hmac_compute_ipad_hash(dd); } static int atmel_sha_hmac_prehash_key(struct atmel_sha_dev *dd, const u8 *key, unsigned int keylen) { return atmel_sha_cpu_hash(dd, key, keylen, true, atmel_sha_hmac_prehash_key_done); } static int atmel_sha_hmac_prehash_key_done(struct atmel_sha_dev *dd) { struct ahash_request *req = dd->req; struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm); struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); size_t ds = crypto_ahash_digestsize(tfm); size_t bs = ctx->block_size; size_t i, num_words = ds / sizeof(u32); /* Prepare ipad. */ for (i = 0; i < num_words; ++i) hmac->ipad[i] = atmel_sha_read(dd, SHA_REG_DIGEST(i)); memset((u8 *)hmac->ipad + ds, 0, bs - ds); return atmel_sha_hmac_compute_ipad_hash(dd); } static int atmel_sha_hmac_compute_ipad_hash(struct atmel_sha_dev *dd) { struct ahash_request *req = dd->req; struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm); struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); size_t bs = ctx->block_size; size_t i, num_words = bs / sizeof(u32); memcpy(hmac->opad, hmac->ipad, bs); for (i = 0; i < num_words; ++i) { hmac->ipad[i] ^= 0x36363636; hmac->opad[i] ^= 0x5c5c5c5c; } return atmel_sha_cpu_hash(dd, hmac->ipad, bs, false, atmel_sha_hmac_compute_opad_hash); } static int atmel_sha_hmac_compute_opad_hash(struct atmel_sha_dev *dd) { struct ahash_request *req = dd->req; struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm); struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); size_t bs = ctx->block_size; size_t hs = ctx->hash_size; size_t i, num_words = hs / sizeof(u32); for (i = 0; i < num_words; ++i) hmac->ipad[i] = atmel_sha_read(dd, SHA_REG_DIGEST(i)); return atmel_sha_cpu_hash(dd, hmac->opad, bs, false, atmel_sha_hmac_setup_done); } static int atmel_sha_hmac_setup_done(struct atmel_sha_dev *dd) { struct ahash_request *req = dd->req; struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm); struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); size_t hs = ctx->hash_size; size_t i, num_words = hs / sizeof(u32); for (i = 0; i < num_words; ++i) hmac->opad[i] = atmel_sha_read(dd, SHA_REG_DIGEST(i)); atmel_sha_hmac_key_release(&hmac->hkey); return hmac->resume(dd); } static int atmel_sha_hmac_start(struct atmel_sha_dev *dd) { struct ahash_request *req = dd->req; struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); int err; err = atmel_sha_hw_init(dd); if (err) return atmel_sha_complete(dd, err); switch (ctx->op) { case SHA_OP_INIT: err = atmel_sha_hmac_setup(dd, atmel_sha_hmac_init_done); break; case SHA_OP_UPDATE: dd->resume = atmel_sha_done; err = atmel_sha_update_req(dd); break; case SHA_OP_FINAL: dd->resume = atmel_sha_hmac_final; err = atmel_sha_final_req(dd); break; case SHA_OP_DIGEST: err = atmel_sha_hmac_setup(dd, atmel_sha_hmac_digest2); break; default: return atmel_sha_complete(dd, -EINVAL); } return err; } static int atmel_sha_hmac_setkey(struct crypto_ahash *tfm, const u8 *key, unsigned int keylen) { struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm); if (atmel_sha_hmac_key_set(&hmac->hkey, key, keylen)) { crypto_ahash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); return -EINVAL; } return 0; } static int atmel_sha_hmac_init(struct ahash_request *req) { int err; err = atmel_sha_init(req); if (err) return err; return atmel_sha_enqueue(req, SHA_OP_INIT); } static int atmel_sha_hmac_init_done(struct atmel_sha_dev *dd) { struct ahash_request *req = dd->req; struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm); size_t bs = ctx->block_size; size_t hs = ctx->hash_size; ctx->bufcnt = 0; ctx->digcnt[0] = bs; ctx->digcnt[1] = 0; ctx->flags |= SHA_FLAGS_RESTORE; memcpy(ctx->digest, hmac->ipad, hs); return atmel_sha_complete(dd, 0); } static int atmel_sha_hmac_final(struct atmel_sha_dev *dd) { struct ahash_request *req = dd->req; struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm); u32 *digest = (u32 *)ctx->digest; size_t ds = crypto_ahash_digestsize(tfm); size_t bs = ctx->block_size; size_t hs = ctx->hash_size; size_t i, num_words; u32 mr; /* Save d = SHA((K' + ipad) | msg). */ num_words = ds / sizeof(u32); for (i = 0; i < num_words; ++i) digest[i] = atmel_sha_read(dd, SHA_REG_DIGEST(i)); /* Restore context to finish computing SHA((K' + opad) | d). */ atmel_sha_write(dd, SHA_CR, SHA_CR_WUIHV); num_words = hs / sizeof(u32); for (i = 0; i < num_words; ++i) atmel_sha_write(dd, SHA_REG_DIN(i), hmac->opad[i]); mr = SHA_MR_MODE_AUTO | SHA_MR_UIHV; mr |= (ctx->flags & SHA_FLAGS_ALGO_MASK); atmel_sha_write(dd, SHA_MR, mr); atmel_sha_write(dd, SHA_MSR, bs + ds); atmel_sha_write(dd, SHA_BCR, ds); atmel_sha_write(dd, SHA_CR, SHA_CR_FIRST); sg_init_one(&dd->tmp, digest, ds); return atmel_sha_cpu_start(dd, &dd->tmp, ds, false, true, atmel_sha_hmac_final_done); } static int atmel_sha_hmac_final_done(struct atmel_sha_dev *dd) { /* * req->result might not be sizeof(u32) aligned, so copy the * digest into ctx->digest[] before memcpy() the data into * req->result. */ atmel_sha_copy_hash(dd->req); atmel_sha_copy_ready_hash(dd->req); return atmel_sha_complete(dd, 0); } static int atmel_sha_hmac_digest(struct ahash_request *req) { int err; err = atmel_sha_init(req); if (err) return err; return atmel_sha_enqueue(req, SHA_OP_DIGEST); } static int atmel_sha_hmac_digest2(struct atmel_sha_dev *dd) { struct ahash_request *req = dd->req; struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm); size_t hs = ctx->hash_size; size_t i, num_words = hs / sizeof(u32); bool use_dma = false; u32 mr; /* Special case for empty message. */ if (!req->nbytes) return atmel_sha_complete(dd, -EINVAL); // TODO: /* Check DMA threshold and alignment. */ if (req->nbytes > ATMEL_SHA_DMA_THRESHOLD && atmel_sha_dma_check_aligned(dd, req->src, req->nbytes)) use_dma = true; /* Write both initial hash values to compute a HMAC. */ atmel_sha_write(dd, SHA_CR, SHA_CR_WUIHV); for (i = 0; i < num_words; ++i) atmel_sha_write(dd, SHA_REG_DIN(i), hmac->ipad[i]); atmel_sha_write(dd, SHA_CR, SHA_CR_WUIEHV); for (i = 0; i < num_words; ++i) atmel_sha_write(dd, SHA_REG_DIN(i), hmac->opad[i]); /* Write the Mode, Message Size, Bytes Count then Control Registers. */ mr = (SHA_MR_HMAC | SHA_MR_DUALBUFF); mr |= ctx->flags & SHA_FLAGS_ALGO_MASK; if (use_dma) mr |= SHA_MR_MODE_IDATAR0; else mr |= SHA_MR_MODE_AUTO; atmel_sha_write(dd, SHA_MR, mr); atmel_sha_write(dd, SHA_MSR, req->nbytes); atmel_sha_write(dd, SHA_BCR, req->nbytes); atmel_sha_write(dd, SHA_CR, SHA_CR_FIRST); /* Process data. */ if (use_dma) return atmel_sha_dma_start(dd, req->src, req->nbytes, atmel_sha_hmac_final_done); return atmel_sha_cpu_start(dd, req->src, req->nbytes, false, true, atmel_sha_hmac_final_done); } static int atmel_sha_hmac_cra_init(struct crypto_tfm *tfm) { struct atmel_sha_hmac_ctx *hmac = crypto_tfm_ctx(tfm); crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), sizeof(struct atmel_sha_reqctx)); hmac->base.start = atmel_sha_hmac_start; atmel_sha_hmac_key_init(&hmac->hkey); return 0; } static void atmel_sha_hmac_cra_exit(struct crypto_tfm *tfm) { struct atmel_sha_hmac_ctx *hmac = crypto_tfm_ctx(tfm); atmel_sha_hmac_key_release(&hmac->hkey); } static struct ahash_alg sha_hmac_algs[] = { { .init = atmel_sha_hmac_init, .update = atmel_sha_update, .final = atmel_sha_final, .digest = atmel_sha_hmac_digest, .setkey = atmel_sha_hmac_setkey, .export = atmel_sha_export, .import = atmel_sha_import, .halg = { .digestsize = SHA1_DIGEST_SIZE, .statesize = sizeof(struct atmel_sha_reqctx), .base = { .cra_name = "hmac(sha1)", .cra_driver_name = "atmel-hmac-sha1", .cra_priority = 100, .cra_flags = CRYPTO_ALG_ASYNC, .cra_blocksize = SHA1_BLOCK_SIZE, .cra_ctxsize = sizeof(struct atmel_sha_hmac_ctx), .cra_alignmask = 0, .cra_module = THIS_MODULE, .cra_init = atmel_sha_hmac_cra_init, .cra_exit = atmel_sha_hmac_cra_exit, } } }, { .init = atmel_sha_hmac_init, .update = atmel_sha_update, .final = atmel_sha_final, .digest = atmel_sha_hmac_digest, .setkey = atmel_sha_hmac_setkey, .export = atmel_sha_export, .import = atmel_sha_import, .halg = { .digestsize = SHA224_DIGEST_SIZE, .statesize = sizeof(struct atmel_sha_reqctx), .base = { .cra_name = "hmac(sha224)", .cra_driver_name = "atmel-hmac-sha224", .cra_priority = 100, .cra_flags = CRYPTO_ALG_ASYNC, .cra_blocksize = SHA224_BLOCK_SIZE, .cra_ctxsize = sizeof(struct atmel_sha_hmac_ctx), .cra_alignmask = 0, .cra_module = THIS_MODULE, .cra_init = atmel_sha_hmac_cra_init, .cra_exit = atmel_sha_hmac_cra_exit, } } }, { .init = atmel_sha_hmac_init, .update = atmel_sha_update, .final = atmel_sha_final, .digest = atmel_sha_hmac_digest, .setkey = atmel_sha_hmac_setkey, .export = atmel_sha_export, .import = atmel_sha_import, .halg = { .digestsize = SHA256_DIGEST_SIZE, .statesize = sizeof(struct atmel_sha_reqctx), .base = { .cra_name = "hmac(sha256)", .cra_driver_name = "atmel-hmac-sha256", .cra_priority = 100, .cra_flags = CRYPTO_ALG_ASYNC, .cra_blocksize = SHA256_BLOCK_SIZE, .cra_ctxsize = sizeof(struct atmel_sha_hmac_ctx), .cra_alignmask = 0, .cra_module = THIS_MODULE, .cra_init = atmel_sha_hmac_cra_init, .cra_exit = atmel_sha_hmac_cra_exit, } } }, { .init = atmel_sha_hmac_init, .update = atmel_sha_update, .final = atmel_sha_final, .digest = atmel_sha_hmac_digest, .setkey = atmel_sha_hmac_setkey, .export = atmel_sha_export, .import = atmel_sha_import, .halg = { .digestsize = SHA384_DIGEST_SIZE, .statesize = sizeof(struct atmel_sha_reqctx), .base = { .cra_name = "hmac(sha384)", .cra_driver_name = "atmel-hmac-sha384", .cra_priority = 100, .cra_flags = CRYPTO_ALG_ASYNC, .cra_blocksize = SHA384_BLOCK_SIZE, .cra_ctxsize = sizeof(struct atmel_sha_hmac_ctx), .cra_alignmask = 0, .cra_module = THIS_MODULE, .cra_init = atmel_sha_hmac_cra_init, .cra_exit = atmel_sha_hmac_cra_exit, } } }, { .init = atmel_sha_hmac_init, .update = atmel_sha_update, .final = atmel_sha_final, .digest = atmel_sha_hmac_digest, .setkey = atmel_sha_hmac_setkey, .export = atmel_sha_export, .import = atmel_sha_import, .halg = { .digestsize = SHA512_DIGEST_SIZE, .statesize = sizeof(struct atmel_sha_reqctx), .base = { .cra_name = "hmac(sha512)", .cra_driver_name = "atmel-hmac-sha512", .cra_priority = 100, .cra_flags = CRYPTO_ALG_ASYNC, .cra_blocksize = SHA512_BLOCK_SIZE, .cra_ctxsize = sizeof(struct atmel_sha_hmac_ctx), .cra_alignmask = 0, .cra_module = THIS_MODULE, .cra_init = atmel_sha_hmac_cra_init, .cra_exit = atmel_sha_hmac_cra_exit, } } }, }; static void atmel_sha_unregister_algs(struct atmel_sha_dev *dd) { int i; if (dd->caps.has_hmac) for (i = 0; i < ARRAY_SIZE(sha_hmac_algs); i++) crypto_unregister_ahash(&sha_hmac_algs[i]); for (i = 0; i < ARRAY_SIZE(sha_1_256_algs); i++) crypto_unregister_ahash(&sha_1_256_algs[i]); Loading Loading @@ -1563,8 +2144,21 @@ static int atmel_sha_register_algs(struct atmel_sha_dev *dd) } } if (dd->caps.has_hmac) { for (i = 0; i < ARRAY_SIZE(sha_hmac_algs); i++) { err = crypto_register_ahash(&sha_hmac_algs[i]); if (err) goto err_sha_hmac_algs; } } return 0; /*i = ARRAY_SIZE(sha_hmac_algs);*/ err_sha_hmac_algs: for (j = 0; j < i; j++) crypto_unregister_ahash(&sha_hmac_algs[j]); i = ARRAY_SIZE(sha_384_512_algs); err_sha_384_512_algs: for (j = 0; j < i; j++) crypto_unregister_ahash(&sha_384_512_algs[j]); Loading Loading @@ -1634,6 +2228,7 @@ static void atmel_sha_get_cap(struct atmel_sha_dev *dd) dd->caps.has_sha224 = 0; dd->caps.has_sha_384_512 = 0; dd->caps.has_uihv = 0; dd->caps.has_hmac = 0; /* keep only major version number */ switch (dd->hw_version & 0xff0) { Loading @@ -1643,6 +2238,7 @@ static void atmel_sha_get_cap(struct atmel_sha_dev *dd) dd->caps.has_sha224 = 1; dd->caps.has_sha_384_512 = 1; dd->caps.has_uihv = 1; dd->caps.has_hmac = 1; break; case 0x420: dd->caps.has_dma = 1; Loading Loading
drivers/crypto/atmel-sha-regs.h +4 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ #define SHA_MR_ALGO_SHA384 (2 << 8) #define SHA_MR_ALGO_SHA512 (3 << 8) #define SHA_MR_ALGO_SHA224 (4 << 8) #define SHA_MR_HMAC (1 << 11) #define SHA_MR_DUALBUFF (1 << 16) #define SHA_IER 0x10 Loading @@ -42,6 +43,9 @@ #define SHA_ISR_URAT_MR (0x2 << 12) #define SHA_ISR_URAT_WO (0x5 << 12) #define SHA_MSR 0x20 #define SHA_BCR 0x30 #define SHA_HW_VERSION 0xFC #define SHA_TPR 0x108 Loading
drivers/crypto/atmel-sha.c +597 −1 Original line number Diff line number Diff line Loading @@ -51,13 +51,20 @@ #define SHA_FLAGS_CPU BIT(5) #define SHA_FLAGS_DMA_READY BIT(6) /* bits[10:8] are reserved. */ /* bits[11:8] are reserved. */ #define SHA_FLAGS_ALGO_MASK SHA_MR_ALGO_MASK #define SHA_FLAGS_SHA1 SHA_MR_ALGO_SHA1 #define SHA_FLAGS_SHA256 SHA_MR_ALGO_SHA256 #define SHA_FLAGS_SHA384 SHA_MR_ALGO_SHA384 #define SHA_FLAGS_SHA512 SHA_MR_ALGO_SHA512 #define SHA_FLAGS_SHA224 SHA_MR_ALGO_SHA224 #define SHA_FLAGS_HMAC SHA_MR_HMAC #define SHA_FLAGS_HMAC_SHA1 (SHA_FLAGS_HMAC | SHA_FLAGS_SHA1) #define SHA_FLAGS_HMAC_SHA256 (SHA_FLAGS_HMAC | SHA_FLAGS_SHA256) #define SHA_FLAGS_HMAC_SHA384 (SHA_FLAGS_HMAC | SHA_FLAGS_SHA384) #define SHA_FLAGS_HMAC_SHA512 (SHA_FLAGS_HMAC | SHA_FLAGS_SHA512) #define SHA_FLAGS_HMAC_SHA224 (SHA_FLAGS_HMAC | SHA_FLAGS_SHA224) #define SHA_FLAGS_MODE_MASK (SHA_FLAGS_HMAC | SHA_FLAGS_ALGO_MASK) #define SHA_FLAGS_FINUP BIT(16) #define SHA_FLAGS_SG BIT(17) Loading @@ -67,8 +74,10 @@ #define SHA_FLAGS_IDATAR0 BIT(26) #define SHA_FLAGS_WAIT_DATARDY BIT(27) #define SHA_OP_INIT 0 #define SHA_OP_UPDATE 1 #define SHA_OP_FINAL 2 #define SHA_OP_DIGEST 3 #define SHA_BUFFER_LEN (PAGE_SIZE / 16) Loading @@ -80,6 +89,7 @@ struct atmel_sha_caps { bool has_sha224; bool has_sha_384_512; bool has_uihv; bool has_hmac; }; struct atmel_sha_dev; Loading @@ -105,6 +115,7 @@ struct atmel_sha_reqctx { unsigned int total; /* total request */ size_t block_size; size_t hash_size; u8 buffer[SHA_BUFFER_LEN + SHA512_BLOCK_SIZE] __aligned(sizeof(u32)); }; Loading Loading @@ -152,6 +163,8 @@ struct atmel_sha_dev { struct atmel_sha_caps caps; struct scatterlist tmp; u32 hw_version; }; Loading Loading @@ -1522,11 +1535,579 @@ static int atmel_sha_cpu_start(struct atmel_sha_dev *dd, return atmel_sha_cpu_transfer(dd); } static int atmel_sha_cpu_hash(struct atmel_sha_dev *dd, const void *data, unsigned int datalen, bool auto_padding, atmel_sha_fn_t resume) { struct ahash_request *req = dd->req; struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); u32 msglen = (auto_padding) ? datalen : 0; u32 mr = SHA_MR_MODE_AUTO; if (!(IS_ALIGNED(datalen, ctx->block_size) || auto_padding)) return atmel_sha_complete(dd, -EINVAL); mr |= (ctx->flags & SHA_FLAGS_ALGO_MASK); atmel_sha_write(dd, SHA_MR, mr); atmel_sha_write(dd, SHA_MSR, msglen); atmel_sha_write(dd, SHA_BCR, msglen); atmel_sha_write(dd, SHA_CR, SHA_CR_FIRST); sg_init_one(&dd->tmp, data, datalen); return atmel_sha_cpu_start(dd, &dd->tmp, datalen, false, true, resume); } /* hmac functions */ struct atmel_sha_hmac_key { bool valid; unsigned int keylen; u8 buffer[SHA512_BLOCK_SIZE]; u8 *keydup; }; static inline void atmel_sha_hmac_key_init(struct atmel_sha_hmac_key *hkey) { memset(hkey, 0, sizeof(*hkey)); } static inline void atmel_sha_hmac_key_release(struct atmel_sha_hmac_key *hkey) { kfree(hkey->keydup); memset(hkey, 0, sizeof(*hkey)); } static inline int atmel_sha_hmac_key_set(struct atmel_sha_hmac_key *hkey, const u8 *key, unsigned int keylen) { atmel_sha_hmac_key_release(hkey); if (keylen > sizeof(hkey->buffer)) { hkey->keydup = kmemdup(key, keylen, GFP_KERNEL); if (!hkey->keydup) return -ENOMEM; } else { memcpy(hkey->buffer, key, keylen); } hkey->valid = true; hkey->keylen = keylen; return 0; } static inline bool atmel_sha_hmac_key_get(const struct atmel_sha_hmac_key *hkey, const u8 **key, unsigned int *keylen) { if (!hkey->valid) return false; *keylen = hkey->keylen; *key = (hkey->keydup) ? hkey->keydup : hkey->buffer; return true; } struct atmel_sha_hmac_ctx { struct atmel_sha_ctx base; struct atmel_sha_hmac_key hkey; u32 ipad[SHA512_BLOCK_SIZE / sizeof(u32)]; u32 opad[SHA512_BLOCK_SIZE / sizeof(u32)]; atmel_sha_fn_t resume; }; static int atmel_sha_hmac_setup(struct atmel_sha_dev *dd, atmel_sha_fn_t resume); static int atmel_sha_hmac_prehash_key(struct atmel_sha_dev *dd, const u8 *key, unsigned int keylen); static int atmel_sha_hmac_prehash_key_done(struct atmel_sha_dev *dd); static int atmel_sha_hmac_compute_ipad_hash(struct atmel_sha_dev *dd); static int atmel_sha_hmac_compute_opad_hash(struct atmel_sha_dev *dd); static int atmel_sha_hmac_setup_done(struct atmel_sha_dev *dd); static int atmel_sha_hmac_init_done(struct atmel_sha_dev *dd); static int atmel_sha_hmac_final(struct atmel_sha_dev *dd); static int atmel_sha_hmac_final_done(struct atmel_sha_dev *dd); static int atmel_sha_hmac_digest2(struct atmel_sha_dev *dd); static int atmel_sha_hmac_setup(struct atmel_sha_dev *dd, atmel_sha_fn_t resume) { struct ahash_request *req = dd->req; struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm); unsigned int keylen; const u8 *key; size_t bs; hmac->resume = resume; switch (ctx->flags & SHA_FLAGS_ALGO_MASK) { case SHA_FLAGS_SHA1: ctx->block_size = SHA1_BLOCK_SIZE; ctx->hash_size = SHA1_DIGEST_SIZE; break; case SHA_FLAGS_SHA224: ctx->block_size = SHA224_BLOCK_SIZE; ctx->hash_size = SHA256_DIGEST_SIZE; break; case SHA_FLAGS_SHA256: ctx->block_size = SHA256_BLOCK_SIZE; ctx->hash_size = SHA256_DIGEST_SIZE; break; case SHA_FLAGS_SHA384: ctx->block_size = SHA384_BLOCK_SIZE; ctx->hash_size = SHA512_DIGEST_SIZE; break; case SHA_FLAGS_SHA512: ctx->block_size = SHA512_BLOCK_SIZE; ctx->hash_size = SHA512_DIGEST_SIZE; break; default: return atmel_sha_complete(dd, -EINVAL); } bs = ctx->block_size; if (likely(!atmel_sha_hmac_key_get(&hmac->hkey, &key, &keylen))) return resume(dd); /* Compute K' from K. */ if (unlikely(keylen > bs)) return atmel_sha_hmac_prehash_key(dd, key, keylen); /* Prepare ipad. */ memcpy((u8 *)hmac->ipad, key, keylen); memset((u8 *)hmac->ipad + keylen, 0, bs - keylen); return atmel_sha_hmac_compute_ipad_hash(dd); } static int atmel_sha_hmac_prehash_key(struct atmel_sha_dev *dd, const u8 *key, unsigned int keylen) { return atmel_sha_cpu_hash(dd, key, keylen, true, atmel_sha_hmac_prehash_key_done); } static int atmel_sha_hmac_prehash_key_done(struct atmel_sha_dev *dd) { struct ahash_request *req = dd->req; struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm); struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); size_t ds = crypto_ahash_digestsize(tfm); size_t bs = ctx->block_size; size_t i, num_words = ds / sizeof(u32); /* Prepare ipad. */ for (i = 0; i < num_words; ++i) hmac->ipad[i] = atmel_sha_read(dd, SHA_REG_DIGEST(i)); memset((u8 *)hmac->ipad + ds, 0, bs - ds); return atmel_sha_hmac_compute_ipad_hash(dd); } static int atmel_sha_hmac_compute_ipad_hash(struct atmel_sha_dev *dd) { struct ahash_request *req = dd->req; struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm); struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); size_t bs = ctx->block_size; size_t i, num_words = bs / sizeof(u32); memcpy(hmac->opad, hmac->ipad, bs); for (i = 0; i < num_words; ++i) { hmac->ipad[i] ^= 0x36363636; hmac->opad[i] ^= 0x5c5c5c5c; } return atmel_sha_cpu_hash(dd, hmac->ipad, bs, false, atmel_sha_hmac_compute_opad_hash); } static int atmel_sha_hmac_compute_opad_hash(struct atmel_sha_dev *dd) { struct ahash_request *req = dd->req; struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm); struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); size_t bs = ctx->block_size; size_t hs = ctx->hash_size; size_t i, num_words = hs / sizeof(u32); for (i = 0; i < num_words; ++i) hmac->ipad[i] = atmel_sha_read(dd, SHA_REG_DIGEST(i)); return atmel_sha_cpu_hash(dd, hmac->opad, bs, false, atmel_sha_hmac_setup_done); } static int atmel_sha_hmac_setup_done(struct atmel_sha_dev *dd) { struct ahash_request *req = dd->req; struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm); struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); size_t hs = ctx->hash_size; size_t i, num_words = hs / sizeof(u32); for (i = 0; i < num_words; ++i) hmac->opad[i] = atmel_sha_read(dd, SHA_REG_DIGEST(i)); atmel_sha_hmac_key_release(&hmac->hkey); return hmac->resume(dd); } static int atmel_sha_hmac_start(struct atmel_sha_dev *dd) { struct ahash_request *req = dd->req; struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); int err; err = atmel_sha_hw_init(dd); if (err) return atmel_sha_complete(dd, err); switch (ctx->op) { case SHA_OP_INIT: err = atmel_sha_hmac_setup(dd, atmel_sha_hmac_init_done); break; case SHA_OP_UPDATE: dd->resume = atmel_sha_done; err = atmel_sha_update_req(dd); break; case SHA_OP_FINAL: dd->resume = atmel_sha_hmac_final; err = atmel_sha_final_req(dd); break; case SHA_OP_DIGEST: err = atmel_sha_hmac_setup(dd, atmel_sha_hmac_digest2); break; default: return atmel_sha_complete(dd, -EINVAL); } return err; } static int atmel_sha_hmac_setkey(struct crypto_ahash *tfm, const u8 *key, unsigned int keylen) { struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm); if (atmel_sha_hmac_key_set(&hmac->hkey, key, keylen)) { crypto_ahash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); return -EINVAL; } return 0; } static int atmel_sha_hmac_init(struct ahash_request *req) { int err; err = atmel_sha_init(req); if (err) return err; return atmel_sha_enqueue(req, SHA_OP_INIT); } static int atmel_sha_hmac_init_done(struct atmel_sha_dev *dd) { struct ahash_request *req = dd->req; struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm); size_t bs = ctx->block_size; size_t hs = ctx->hash_size; ctx->bufcnt = 0; ctx->digcnt[0] = bs; ctx->digcnt[1] = 0; ctx->flags |= SHA_FLAGS_RESTORE; memcpy(ctx->digest, hmac->ipad, hs); return atmel_sha_complete(dd, 0); } static int atmel_sha_hmac_final(struct atmel_sha_dev *dd) { struct ahash_request *req = dd->req; struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm); u32 *digest = (u32 *)ctx->digest; size_t ds = crypto_ahash_digestsize(tfm); size_t bs = ctx->block_size; size_t hs = ctx->hash_size; size_t i, num_words; u32 mr; /* Save d = SHA((K' + ipad) | msg). */ num_words = ds / sizeof(u32); for (i = 0; i < num_words; ++i) digest[i] = atmel_sha_read(dd, SHA_REG_DIGEST(i)); /* Restore context to finish computing SHA((K' + opad) | d). */ atmel_sha_write(dd, SHA_CR, SHA_CR_WUIHV); num_words = hs / sizeof(u32); for (i = 0; i < num_words; ++i) atmel_sha_write(dd, SHA_REG_DIN(i), hmac->opad[i]); mr = SHA_MR_MODE_AUTO | SHA_MR_UIHV; mr |= (ctx->flags & SHA_FLAGS_ALGO_MASK); atmel_sha_write(dd, SHA_MR, mr); atmel_sha_write(dd, SHA_MSR, bs + ds); atmel_sha_write(dd, SHA_BCR, ds); atmel_sha_write(dd, SHA_CR, SHA_CR_FIRST); sg_init_one(&dd->tmp, digest, ds); return atmel_sha_cpu_start(dd, &dd->tmp, ds, false, true, atmel_sha_hmac_final_done); } static int atmel_sha_hmac_final_done(struct atmel_sha_dev *dd) { /* * req->result might not be sizeof(u32) aligned, so copy the * digest into ctx->digest[] before memcpy() the data into * req->result. */ atmel_sha_copy_hash(dd->req); atmel_sha_copy_ready_hash(dd->req); return atmel_sha_complete(dd, 0); } static int atmel_sha_hmac_digest(struct ahash_request *req) { int err; err = atmel_sha_init(req); if (err) return err; return atmel_sha_enqueue(req, SHA_OP_DIGEST); } static int atmel_sha_hmac_digest2(struct atmel_sha_dev *dd) { struct ahash_request *req = dd->req; struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm); size_t hs = ctx->hash_size; size_t i, num_words = hs / sizeof(u32); bool use_dma = false; u32 mr; /* Special case for empty message. */ if (!req->nbytes) return atmel_sha_complete(dd, -EINVAL); // TODO: /* Check DMA threshold and alignment. */ if (req->nbytes > ATMEL_SHA_DMA_THRESHOLD && atmel_sha_dma_check_aligned(dd, req->src, req->nbytes)) use_dma = true; /* Write both initial hash values to compute a HMAC. */ atmel_sha_write(dd, SHA_CR, SHA_CR_WUIHV); for (i = 0; i < num_words; ++i) atmel_sha_write(dd, SHA_REG_DIN(i), hmac->ipad[i]); atmel_sha_write(dd, SHA_CR, SHA_CR_WUIEHV); for (i = 0; i < num_words; ++i) atmel_sha_write(dd, SHA_REG_DIN(i), hmac->opad[i]); /* Write the Mode, Message Size, Bytes Count then Control Registers. */ mr = (SHA_MR_HMAC | SHA_MR_DUALBUFF); mr |= ctx->flags & SHA_FLAGS_ALGO_MASK; if (use_dma) mr |= SHA_MR_MODE_IDATAR0; else mr |= SHA_MR_MODE_AUTO; atmel_sha_write(dd, SHA_MR, mr); atmel_sha_write(dd, SHA_MSR, req->nbytes); atmel_sha_write(dd, SHA_BCR, req->nbytes); atmel_sha_write(dd, SHA_CR, SHA_CR_FIRST); /* Process data. */ if (use_dma) return atmel_sha_dma_start(dd, req->src, req->nbytes, atmel_sha_hmac_final_done); return atmel_sha_cpu_start(dd, req->src, req->nbytes, false, true, atmel_sha_hmac_final_done); } static int atmel_sha_hmac_cra_init(struct crypto_tfm *tfm) { struct atmel_sha_hmac_ctx *hmac = crypto_tfm_ctx(tfm); crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), sizeof(struct atmel_sha_reqctx)); hmac->base.start = atmel_sha_hmac_start; atmel_sha_hmac_key_init(&hmac->hkey); return 0; } static void atmel_sha_hmac_cra_exit(struct crypto_tfm *tfm) { struct atmel_sha_hmac_ctx *hmac = crypto_tfm_ctx(tfm); atmel_sha_hmac_key_release(&hmac->hkey); } static struct ahash_alg sha_hmac_algs[] = { { .init = atmel_sha_hmac_init, .update = atmel_sha_update, .final = atmel_sha_final, .digest = atmel_sha_hmac_digest, .setkey = atmel_sha_hmac_setkey, .export = atmel_sha_export, .import = atmel_sha_import, .halg = { .digestsize = SHA1_DIGEST_SIZE, .statesize = sizeof(struct atmel_sha_reqctx), .base = { .cra_name = "hmac(sha1)", .cra_driver_name = "atmel-hmac-sha1", .cra_priority = 100, .cra_flags = CRYPTO_ALG_ASYNC, .cra_blocksize = SHA1_BLOCK_SIZE, .cra_ctxsize = sizeof(struct atmel_sha_hmac_ctx), .cra_alignmask = 0, .cra_module = THIS_MODULE, .cra_init = atmel_sha_hmac_cra_init, .cra_exit = atmel_sha_hmac_cra_exit, } } }, { .init = atmel_sha_hmac_init, .update = atmel_sha_update, .final = atmel_sha_final, .digest = atmel_sha_hmac_digest, .setkey = atmel_sha_hmac_setkey, .export = atmel_sha_export, .import = atmel_sha_import, .halg = { .digestsize = SHA224_DIGEST_SIZE, .statesize = sizeof(struct atmel_sha_reqctx), .base = { .cra_name = "hmac(sha224)", .cra_driver_name = "atmel-hmac-sha224", .cra_priority = 100, .cra_flags = CRYPTO_ALG_ASYNC, .cra_blocksize = SHA224_BLOCK_SIZE, .cra_ctxsize = sizeof(struct atmel_sha_hmac_ctx), .cra_alignmask = 0, .cra_module = THIS_MODULE, .cra_init = atmel_sha_hmac_cra_init, .cra_exit = atmel_sha_hmac_cra_exit, } } }, { .init = atmel_sha_hmac_init, .update = atmel_sha_update, .final = atmel_sha_final, .digest = atmel_sha_hmac_digest, .setkey = atmel_sha_hmac_setkey, .export = atmel_sha_export, .import = atmel_sha_import, .halg = { .digestsize = SHA256_DIGEST_SIZE, .statesize = sizeof(struct atmel_sha_reqctx), .base = { .cra_name = "hmac(sha256)", .cra_driver_name = "atmel-hmac-sha256", .cra_priority = 100, .cra_flags = CRYPTO_ALG_ASYNC, .cra_blocksize = SHA256_BLOCK_SIZE, .cra_ctxsize = sizeof(struct atmel_sha_hmac_ctx), .cra_alignmask = 0, .cra_module = THIS_MODULE, .cra_init = atmel_sha_hmac_cra_init, .cra_exit = atmel_sha_hmac_cra_exit, } } }, { .init = atmel_sha_hmac_init, .update = atmel_sha_update, .final = atmel_sha_final, .digest = atmel_sha_hmac_digest, .setkey = atmel_sha_hmac_setkey, .export = atmel_sha_export, .import = atmel_sha_import, .halg = { .digestsize = SHA384_DIGEST_SIZE, .statesize = sizeof(struct atmel_sha_reqctx), .base = { .cra_name = "hmac(sha384)", .cra_driver_name = "atmel-hmac-sha384", .cra_priority = 100, .cra_flags = CRYPTO_ALG_ASYNC, .cra_blocksize = SHA384_BLOCK_SIZE, .cra_ctxsize = sizeof(struct atmel_sha_hmac_ctx), .cra_alignmask = 0, .cra_module = THIS_MODULE, .cra_init = atmel_sha_hmac_cra_init, .cra_exit = atmel_sha_hmac_cra_exit, } } }, { .init = atmel_sha_hmac_init, .update = atmel_sha_update, .final = atmel_sha_final, .digest = atmel_sha_hmac_digest, .setkey = atmel_sha_hmac_setkey, .export = atmel_sha_export, .import = atmel_sha_import, .halg = { .digestsize = SHA512_DIGEST_SIZE, .statesize = sizeof(struct atmel_sha_reqctx), .base = { .cra_name = "hmac(sha512)", .cra_driver_name = "atmel-hmac-sha512", .cra_priority = 100, .cra_flags = CRYPTO_ALG_ASYNC, .cra_blocksize = SHA512_BLOCK_SIZE, .cra_ctxsize = sizeof(struct atmel_sha_hmac_ctx), .cra_alignmask = 0, .cra_module = THIS_MODULE, .cra_init = atmel_sha_hmac_cra_init, .cra_exit = atmel_sha_hmac_cra_exit, } } }, }; static void atmel_sha_unregister_algs(struct atmel_sha_dev *dd) { int i; if (dd->caps.has_hmac) for (i = 0; i < ARRAY_SIZE(sha_hmac_algs); i++) crypto_unregister_ahash(&sha_hmac_algs[i]); for (i = 0; i < ARRAY_SIZE(sha_1_256_algs); i++) crypto_unregister_ahash(&sha_1_256_algs[i]); Loading Loading @@ -1563,8 +2144,21 @@ static int atmel_sha_register_algs(struct atmel_sha_dev *dd) } } if (dd->caps.has_hmac) { for (i = 0; i < ARRAY_SIZE(sha_hmac_algs); i++) { err = crypto_register_ahash(&sha_hmac_algs[i]); if (err) goto err_sha_hmac_algs; } } return 0; /*i = ARRAY_SIZE(sha_hmac_algs);*/ err_sha_hmac_algs: for (j = 0; j < i; j++) crypto_unregister_ahash(&sha_hmac_algs[j]); i = ARRAY_SIZE(sha_384_512_algs); err_sha_384_512_algs: for (j = 0; j < i; j++) crypto_unregister_ahash(&sha_384_512_algs[j]); Loading Loading @@ -1634,6 +2228,7 @@ static void atmel_sha_get_cap(struct atmel_sha_dev *dd) dd->caps.has_sha224 = 0; dd->caps.has_sha_384_512 = 0; dd->caps.has_uihv = 0; dd->caps.has_hmac = 0; /* keep only major version number */ switch (dd->hw_version & 0xff0) { Loading @@ -1643,6 +2238,7 @@ static void atmel_sha_get_cap(struct atmel_sha_dev *dd) dd->caps.has_sha224 = 1; dd->caps.has_sha_384_512 = 1; dd->caps.has_uihv = 1; dd->caps.has_hmac = 1; break; case 0x420: dd->caps.has_dma = 1; Loading