📄 padlock-sha.c
字号:
/* * Cryptographic API. * * Support for VIA PadLock hardware crypto engine. * * Copyright (c) 2006 Michal Ludvig <michal@logix.cz> * * 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 of the License, or * (at your option) any later version. * */#include <crypto/algapi.h>#include <crypto/sha.h>#include <linux/err.h>#include <linux/module.h>#include <linux/init.h>#include <linux/errno.h>#include <linux/cryptohash.h>#include <linux/interrupt.h>#include <linux/kernel.h>#include <linux/scatterlist.h>#include "padlock.h"#define SHA1_DEFAULT_FALLBACK "sha1-generic"#define SHA256_DEFAULT_FALLBACK "sha256-generic"struct padlock_sha_ctx { char *data; size_t used; int bypass; void (*f_sha_padlock)(const char *in, char *out, int count); struct hash_desc fallback;};static inline struct padlock_sha_ctx *ctx(struct crypto_tfm *tfm){ return crypto_tfm_ctx(tfm);}/* We'll need aligned address on the stack */#define NEAREST_ALIGNED(ptr) \ ((void *)ALIGN((size_t)(ptr), PADLOCK_ALIGNMENT))static struct crypto_alg sha1_alg, sha256_alg;static void padlock_sha_bypass(struct crypto_tfm *tfm){ if (ctx(tfm)->bypass) return; crypto_hash_init(&ctx(tfm)->fallback); if (ctx(tfm)->data && ctx(tfm)->used) { struct scatterlist sg; sg_init_one(&sg, ctx(tfm)->data, ctx(tfm)->used); crypto_hash_update(&ctx(tfm)->fallback, &sg, sg.length); } ctx(tfm)->used = 0; ctx(tfm)->bypass = 1;}static void padlock_sha_init(struct crypto_tfm *tfm){ ctx(tfm)->used = 0; ctx(tfm)->bypass = 0;}static void padlock_sha_update(struct crypto_tfm *tfm, const uint8_t *data, unsigned int length){ /* Our buffer is always one page. */ if (unlikely(!ctx(tfm)->bypass && (ctx(tfm)->used + length > PAGE_SIZE))) padlock_sha_bypass(tfm); if (unlikely(ctx(tfm)->bypass)) { struct scatterlist sg; sg_init_one(&sg, (uint8_t *)data, length); crypto_hash_update(&ctx(tfm)->fallback, &sg, length); return; } memcpy(ctx(tfm)->data + ctx(tfm)->used, data, length); ctx(tfm)->used += length;}static inline void padlock_output_block(uint32_t *src, uint32_t *dst, size_t count){ while (count--) *dst++ = swab32(*src++);}static void padlock_do_sha1(const char *in, char *out, int count){ /* We can't store directly to *out as it may be unaligned. */ /* BTW Don't reduce the buffer size below 128 Bytes! * PadLock microcode needs it that big. */ char buf[128+16]; char *result = NEAREST_ALIGNED(buf); ((uint32_t *)result)[0] = SHA1_H0; ((uint32_t *)result)[1] = SHA1_H1; ((uint32_t *)result)[2] = SHA1_H2; ((uint32_t *)result)[3] = SHA1_H3; ((uint32_t *)result)[4] = SHA1_H4; asm volatile (".byte 0xf3,0x0f,0xa6,0xc8" /* rep xsha1 */ : "+S"(in), "+D"(result) : "c"(count), "a"(0)); padlock_output_block((uint32_t *)result, (uint32_t *)out, 5);}static void padlock_do_sha256(const char *in, char *out, int count){ /* We can't store directly to *out as it may be unaligned. */ /* BTW Don't reduce the buffer size below 128 Bytes! * PadLock microcode needs it that big. */ char buf[128+16]; char *result = NEAREST_ALIGNED(buf); ((uint32_t *)result)[0] = SHA256_H0; ((uint32_t *)result)[1] = SHA256_H1; ((uint32_t *)result)[2] = SHA256_H2; ((uint32_t *)result)[3] = SHA256_H3; ((uint32_t *)result)[4] = SHA256_H4; ((uint32_t *)result)[5] = SHA256_H5; ((uint32_t *)result)[6] = SHA256_H6; ((uint32_t *)result)[7] = SHA256_H7; asm volatile (".byte 0xf3,0x0f,0xa6,0xd0" /* rep xsha256 */ : "+S"(in), "+D"(result) : "c"(count), "a"(0)); padlock_output_block((uint32_t *)result, (uint32_t *)out, 8);}static void padlock_sha_final(struct crypto_tfm *tfm, uint8_t *out){ if (unlikely(ctx(tfm)->bypass)) { crypto_hash_final(&ctx(tfm)->fallback, out); ctx(tfm)->bypass = 0; return; } /* Pass the input buffer to PadLock microcode... */ ctx(tfm)->f_sha_padlock(ctx(tfm)->data, out, ctx(tfm)->used); ctx(tfm)->used = 0;}static int padlock_cra_init(struct crypto_tfm *tfm){ const char *fallback_driver_name = tfm->__crt_alg->cra_name; struct crypto_hash *fallback_tfm; /* For now we'll allocate one page. This * could eventually be configurable one day. */ ctx(tfm)->data = (char *)__get_free_page(GFP_KERNEL); if (!ctx(tfm)->data) return -ENOMEM; /* Allocate a fallback and abort if it failed. */ fallback_tfm = crypto_alloc_hash(fallback_driver_name, 0, CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK); if (IS_ERR(fallback_tfm)) { printk(KERN_WARNING PFX "Fallback driver '%s' could not be loaded!\n", fallback_driver_name); free_page((unsigned long)(ctx(tfm)->data)); return PTR_ERR(fallback_tfm); } ctx(tfm)->fallback.tfm = fallback_tfm; return 0;}static int padlock_sha1_cra_init(struct crypto_tfm *tfm){ ctx(tfm)->f_sha_padlock = padlock_do_sha1; return padlock_cra_init(tfm);}static int padlock_sha256_cra_init(struct crypto_tfm *tfm){ ctx(tfm)->f_sha_padlock = padlock_do_sha256; return padlock_cra_init(tfm);}static void padlock_cra_exit(struct crypto_tfm *tfm){ if (ctx(tfm)->data) { free_page((unsigned long)(ctx(tfm)->data)); ctx(tfm)->data = NULL; } crypto_free_hash(ctx(tfm)->fallback.tfm); ctx(tfm)->fallback.tfm = NULL;}static struct crypto_alg sha1_alg = { .cra_name = "sha1", .cra_driver_name = "sha1-padlock", .cra_priority = PADLOCK_CRA_PRIORITY, .cra_flags = CRYPTO_ALG_TYPE_DIGEST | CRYPTO_ALG_NEED_FALLBACK, .cra_blocksize = SHA1_BLOCK_SIZE, .cra_ctxsize = sizeof(struct padlock_sha_ctx), .cra_module = THIS_MODULE, .cra_list = LIST_HEAD_INIT(sha1_alg.cra_list), .cra_init = padlock_sha1_cra_init, .cra_exit = padlock_cra_exit, .cra_u = { .digest = { .dia_digestsize = SHA1_DIGEST_SIZE, .dia_init = padlock_sha_init, .dia_update = padlock_sha_update, .dia_final = padlock_sha_final, } }};static struct crypto_alg sha256_alg = { .cra_name = "sha256", .cra_driver_name = "sha256-padlock", .cra_priority = PADLOCK_CRA_PRIORITY, .cra_flags = CRYPTO_ALG_TYPE_DIGEST | CRYPTO_ALG_NEED_FALLBACK, .cra_blocksize = SHA256_BLOCK_SIZE, .cra_ctxsize = sizeof(struct padlock_sha_ctx), .cra_module = THIS_MODULE, .cra_list = LIST_HEAD_INIT(sha256_alg.cra_list), .cra_init = padlock_sha256_cra_init, .cra_exit = padlock_cra_exit, .cra_u = { .digest = { .dia_digestsize = SHA256_DIGEST_SIZE, .dia_init = padlock_sha_init, .dia_update = padlock_sha_update, .dia_final = padlock_sha_final, } }};static int __init padlock_init(void){ int rc = -ENODEV; if (!cpu_has_phe) { printk(KERN_ERR PFX "VIA PadLock Hash Engine not detected.\n"); return -ENODEV; } if (!cpu_has_phe_enabled) { printk(KERN_ERR PFX "VIA PadLock detected, but not enabled. Hmm, strange...\n"); return -ENODEV; } rc = crypto_register_alg(&sha1_alg); if (rc) goto out; rc = crypto_register_alg(&sha256_alg); if (rc) goto out_unreg1; printk(KERN_NOTICE PFX "Using VIA PadLock ACE for SHA1/SHA256 algorithms.\n"); return 0;out_unreg1: crypto_unregister_alg(&sha1_alg);out: printk(KERN_ERR PFX "VIA PadLock SHA1/SHA256 initialization failed.\n"); return rc;}static void __exit padlock_fini(void){ crypto_unregister_alg(&sha1_alg); crypto_unregister_alg(&sha256_alg);}module_init(padlock_init);module_exit(padlock_fini);MODULE_DESCRIPTION("VIA PadLock SHA1/SHA256 algorithms support.");MODULE_LICENSE("GPL");MODULE_AUTHOR("Michal Ludvig");MODULE_ALIAS("sha1");MODULE_ALIAS("sha256");MODULE_ALIAS("sha1-padlock");MODULE_ALIAS("sha256-padlock");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -