18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Linux/arm64 port of the OpenSSL SHA256 implementation for AArch64 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2016 Linaro Ltd. <ard.biesheuvel@linaro.org> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <asm/hwcap.h> 98c2ecf20Sopenharmony_ci#include <asm/neon.h> 108c2ecf20Sopenharmony_ci#include <asm/simd.h> 118c2ecf20Sopenharmony_ci#include <crypto/internal/hash.h> 128c2ecf20Sopenharmony_ci#include <crypto/internal/simd.h> 138c2ecf20Sopenharmony_ci#include <crypto/sha.h> 148c2ecf20Sopenharmony_ci#include <crypto/sha256_base.h> 158c2ecf20Sopenharmony_ci#include <linux/types.h> 168c2ecf20Sopenharmony_ci#include <linux/string.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("SHA-224/SHA-256 secure hash for arm64"); 198c2ecf20Sopenharmony_ciMODULE_AUTHOR("Andy Polyakov <appro@openssl.org>"); 208c2ecf20Sopenharmony_ciMODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>"); 218c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 228c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("sha224"); 238c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("sha256"); 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ciasmlinkage void sha256_block_data_order(u32 *digest, const void *data, 268c2ecf20Sopenharmony_ci unsigned int num_blks); 278c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sha256_block_data_order); 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic void __sha256_block_data_order(struct sha256_state *sst, u8 const *src, 308c2ecf20Sopenharmony_ci int blocks) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci sha256_block_data_order(sst->state, src, blocks); 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ciasmlinkage void sha256_block_neon(u32 *digest, const void *data, 368c2ecf20Sopenharmony_ci unsigned int num_blks); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic void __sha256_block_neon(struct sha256_state *sst, u8 const *src, 398c2ecf20Sopenharmony_ci int blocks) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci sha256_block_neon(sst->state, src, blocks); 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic int crypto_sha256_arm64_update(struct shash_desc *desc, const u8 *data, 458c2ecf20Sopenharmony_ci unsigned int len) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci return sha256_base_do_update(desc, data, len, 488c2ecf20Sopenharmony_ci __sha256_block_data_order); 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic int crypto_sha256_arm64_finup(struct shash_desc *desc, const u8 *data, 528c2ecf20Sopenharmony_ci unsigned int len, u8 *out) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci if (len) 558c2ecf20Sopenharmony_ci sha256_base_do_update(desc, data, len, 568c2ecf20Sopenharmony_ci __sha256_block_data_order); 578c2ecf20Sopenharmony_ci sha256_base_do_finalize(desc, __sha256_block_data_order); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci return sha256_base_finish(desc, out); 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic int crypto_sha256_arm64_final(struct shash_desc *desc, u8 *out) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci return crypto_sha256_arm64_finup(desc, NULL, 0, out); 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic struct shash_alg algs[] = { { 688c2ecf20Sopenharmony_ci .digestsize = SHA256_DIGEST_SIZE, 698c2ecf20Sopenharmony_ci .init = sha256_base_init, 708c2ecf20Sopenharmony_ci .update = crypto_sha256_arm64_update, 718c2ecf20Sopenharmony_ci .final = crypto_sha256_arm64_final, 728c2ecf20Sopenharmony_ci .finup = crypto_sha256_arm64_finup, 738c2ecf20Sopenharmony_ci .descsize = sizeof(struct sha256_state), 748c2ecf20Sopenharmony_ci .base.cra_name = "sha256", 758c2ecf20Sopenharmony_ci .base.cra_driver_name = "sha256-arm64", 768c2ecf20Sopenharmony_ci .base.cra_priority = 125, 778c2ecf20Sopenharmony_ci .base.cra_blocksize = SHA256_BLOCK_SIZE, 788c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 798c2ecf20Sopenharmony_ci}, { 808c2ecf20Sopenharmony_ci .digestsize = SHA224_DIGEST_SIZE, 818c2ecf20Sopenharmony_ci .init = sha224_base_init, 828c2ecf20Sopenharmony_ci .update = crypto_sha256_arm64_update, 838c2ecf20Sopenharmony_ci .final = crypto_sha256_arm64_final, 848c2ecf20Sopenharmony_ci .finup = crypto_sha256_arm64_finup, 858c2ecf20Sopenharmony_ci .descsize = sizeof(struct sha256_state), 868c2ecf20Sopenharmony_ci .base.cra_name = "sha224", 878c2ecf20Sopenharmony_ci .base.cra_driver_name = "sha224-arm64", 888c2ecf20Sopenharmony_ci .base.cra_priority = 125, 898c2ecf20Sopenharmony_ci .base.cra_blocksize = SHA224_BLOCK_SIZE, 908c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 918c2ecf20Sopenharmony_ci} }; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic int sha256_update_neon(struct shash_desc *desc, const u8 *data, 948c2ecf20Sopenharmony_ci unsigned int len) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci struct sha256_state *sctx = shash_desc_ctx(desc); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci if (!crypto_simd_usable()) 998c2ecf20Sopenharmony_ci return sha256_base_do_update(desc, data, len, 1008c2ecf20Sopenharmony_ci __sha256_block_data_order); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci while (len > 0) { 1038c2ecf20Sopenharmony_ci unsigned int chunk = len; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci /* 1068c2ecf20Sopenharmony_ci * Don't hog the CPU for the entire time it takes to process all 1078c2ecf20Sopenharmony_ci * input when running on a preemptible kernel, but process the 1088c2ecf20Sopenharmony_ci * data block by block instead. 1098c2ecf20Sopenharmony_ci */ 1108c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_PREEMPTION) && 1118c2ecf20Sopenharmony_ci chunk + sctx->count % SHA256_BLOCK_SIZE > SHA256_BLOCK_SIZE) 1128c2ecf20Sopenharmony_ci chunk = SHA256_BLOCK_SIZE - 1138c2ecf20Sopenharmony_ci sctx->count % SHA256_BLOCK_SIZE; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci kernel_neon_begin(); 1168c2ecf20Sopenharmony_ci sha256_base_do_update(desc, data, chunk, __sha256_block_neon); 1178c2ecf20Sopenharmony_ci kernel_neon_end(); 1188c2ecf20Sopenharmony_ci data += chunk; 1198c2ecf20Sopenharmony_ci len -= chunk; 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci return 0; 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic int sha256_finup_neon(struct shash_desc *desc, const u8 *data, 1258c2ecf20Sopenharmony_ci unsigned int len, u8 *out) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci if (!crypto_simd_usable()) { 1288c2ecf20Sopenharmony_ci if (len) 1298c2ecf20Sopenharmony_ci sha256_base_do_update(desc, data, len, 1308c2ecf20Sopenharmony_ci __sha256_block_data_order); 1318c2ecf20Sopenharmony_ci sha256_base_do_finalize(desc, __sha256_block_data_order); 1328c2ecf20Sopenharmony_ci } else { 1338c2ecf20Sopenharmony_ci if (len) 1348c2ecf20Sopenharmony_ci sha256_update_neon(desc, data, len); 1358c2ecf20Sopenharmony_ci kernel_neon_begin(); 1368c2ecf20Sopenharmony_ci sha256_base_do_finalize(desc, __sha256_block_neon); 1378c2ecf20Sopenharmony_ci kernel_neon_end(); 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci return sha256_base_finish(desc, out); 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic int sha256_final_neon(struct shash_desc *desc, u8 *out) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci return sha256_finup_neon(desc, NULL, 0, out); 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic struct shash_alg neon_algs[] = { { 1488c2ecf20Sopenharmony_ci .digestsize = SHA256_DIGEST_SIZE, 1498c2ecf20Sopenharmony_ci .init = sha256_base_init, 1508c2ecf20Sopenharmony_ci .update = sha256_update_neon, 1518c2ecf20Sopenharmony_ci .final = sha256_final_neon, 1528c2ecf20Sopenharmony_ci .finup = sha256_finup_neon, 1538c2ecf20Sopenharmony_ci .descsize = sizeof(struct sha256_state), 1548c2ecf20Sopenharmony_ci .base.cra_name = "sha256", 1558c2ecf20Sopenharmony_ci .base.cra_driver_name = "sha256-arm64-neon", 1568c2ecf20Sopenharmony_ci .base.cra_priority = 150, 1578c2ecf20Sopenharmony_ci .base.cra_blocksize = SHA256_BLOCK_SIZE, 1588c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 1598c2ecf20Sopenharmony_ci}, { 1608c2ecf20Sopenharmony_ci .digestsize = SHA224_DIGEST_SIZE, 1618c2ecf20Sopenharmony_ci .init = sha224_base_init, 1628c2ecf20Sopenharmony_ci .update = sha256_update_neon, 1638c2ecf20Sopenharmony_ci .final = sha256_final_neon, 1648c2ecf20Sopenharmony_ci .finup = sha256_finup_neon, 1658c2ecf20Sopenharmony_ci .descsize = sizeof(struct sha256_state), 1668c2ecf20Sopenharmony_ci .base.cra_name = "sha224", 1678c2ecf20Sopenharmony_ci .base.cra_driver_name = "sha224-arm64-neon", 1688c2ecf20Sopenharmony_ci .base.cra_priority = 150, 1698c2ecf20Sopenharmony_ci .base.cra_blocksize = SHA224_BLOCK_SIZE, 1708c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 1718c2ecf20Sopenharmony_ci} }; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic int __init sha256_mod_init(void) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci int ret = crypto_register_shashes(algs, ARRAY_SIZE(algs)); 1768c2ecf20Sopenharmony_ci if (ret) 1778c2ecf20Sopenharmony_ci return ret; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci if (cpu_have_named_feature(ASIMD)) { 1808c2ecf20Sopenharmony_ci ret = crypto_register_shashes(neon_algs, ARRAY_SIZE(neon_algs)); 1818c2ecf20Sopenharmony_ci if (ret) 1828c2ecf20Sopenharmony_ci crypto_unregister_shashes(algs, ARRAY_SIZE(algs)); 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci return ret; 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistatic void __exit sha256_mod_fini(void) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci if (cpu_have_named_feature(ASIMD)) 1908c2ecf20Sopenharmony_ci crypto_unregister_shashes(neon_algs, ARRAY_SIZE(neon_algs)); 1918c2ecf20Sopenharmony_ci crypto_unregister_shashes(algs, ARRAY_SIZE(algs)); 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cimodule_init(sha256_mod_init); 1958c2ecf20Sopenharmony_cimodule_exit(sha256_mod_fini); 196