18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Glue code for MD5 implementation for PPC assembler 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Based on generic implementation. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (c) 2015 Markus Stockhausen <stockhausen@collogia.de> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <crypto/internal/hash.h> 118c2ecf20Sopenharmony_ci#include <linux/init.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/mm.h> 148c2ecf20Sopenharmony_ci#include <linux/types.h> 158c2ecf20Sopenharmony_ci#include <crypto/md5.h> 168c2ecf20Sopenharmony_ci#include <asm/byteorder.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ciextern void ppc_md5_transform(u32 *state, const u8 *src, u32 blocks); 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic inline void ppc_md5_clear_context(struct md5_state *sctx) 218c2ecf20Sopenharmony_ci{ 228c2ecf20Sopenharmony_ci int count = sizeof(struct md5_state) >> 2; 238c2ecf20Sopenharmony_ci u32 *ptr = (u32 *)sctx; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci /* make sure we can clear the fast way */ 268c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct md5_state) % 4); 278c2ecf20Sopenharmony_ci do { *ptr++ = 0; } while (--count); 288c2ecf20Sopenharmony_ci} 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic int ppc_md5_init(struct shash_desc *desc) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci struct md5_state *sctx = shash_desc_ctx(desc); 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci sctx->hash[0] = MD5_H0; 358c2ecf20Sopenharmony_ci sctx->hash[1] = MD5_H1; 368c2ecf20Sopenharmony_ci sctx->hash[2] = MD5_H2; 378c2ecf20Sopenharmony_ci sctx->hash[3] = MD5_H3; 388c2ecf20Sopenharmony_ci sctx->byte_count = 0; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci return 0; 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic int ppc_md5_update(struct shash_desc *desc, const u8 *data, 448c2ecf20Sopenharmony_ci unsigned int len) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci struct md5_state *sctx = shash_desc_ctx(desc); 478c2ecf20Sopenharmony_ci const unsigned int offset = sctx->byte_count & 0x3f; 488c2ecf20Sopenharmony_ci unsigned int avail = 64 - offset; 498c2ecf20Sopenharmony_ci const u8 *src = data; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci sctx->byte_count += len; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci if (avail > len) { 548c2ecf20Sopenharmony_ci memcpy((char *)sctx->block + offset, src, len); 558c2ecf20Sopenharmony_ci return 0; 568c2ecf20Sopenharmony_ci } 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci if (offset) { 598c2ecf20Sopenharmony_ci memcpy((char *)sctx->block + offset, src, avail); 608c2ecf20Sopenharmony_ci ppc_md5_transform(sctx->hash, (const u8 *)sctx->block, 1); 618c2ecf20Sopenharmony_ci len -= avail; 628c2ecf20Sopenharmony_ci src += avail; 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci if (len > 63) { 668c2ecf20Sopenharmony_ci ppc_md5_transform(sctx->hash, src, len >> 6); 678c2ecf20Sopenharmony_ci src += len & ~0x3f; 688c2ecf20Sopenharmony_ci len &= 0x3f; 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci memcpy((char *)sctx->block, src, len); 728c2ecf20Sopenharmony_ci return 0; 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic int ppc_md5_final(struct shash_desc *desc, u8 *out) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci struct md5_state *sctx = shash_desc_ctx(desc); 788c2ecf20Sopenharmony_ci const unsigned int offset = sctx->byte_count & 0x3f; 798c2ecf20Sopenharmony_ci const u8 *src = (const u8 *)sctx->block; 808c2ecf20Sopenharmony_ci u8 *p = (u8 *)src + offset; 818c2ecf20Sopenharmony_ci int padlen = 55 - offset; 828c2ecf20Sopenharmony_ci __le64 *pbits = (__le64 *)((char *)sctx->block + 56); 838c2ecf20Sopenharmony_ci __le32 *dst = (__le32 *)out; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci *p++ = 0x80; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci if (padlen < 0) { 888c2ecf20Sopenharmony_ci memset(p, 0x00, padlen + sizeof (u64)); 898c2ecf20Sopenharmony_ci ppc_md5_transform(sctx->hash, src, 1); 908c2ecf20Sopenharmony_ci p = (char *)sctx->block; 918c2ecf20Sopenharmony_ci padlen = 56; 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci memset(p, 0, padlen); 958c2ecf20Sopenharmony_ci *pbits = cpu_to_le64(sctx->byte_count << 3); 968c2ecf20Sopenharmony_ci ppc_md5_transform(sctx->hash, src, 1); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci dst[0] = cpu_to_le32(sctx->hash[0]); 998c2ecf20Sopenharmony_ci dst[1] = cpu_to_le32(sctx->hash[1]); 1008c2ecf20Sopenharmony_ci dst[2] = cpu_to_le32(sctx->hash[2]); 1018c2ecf20Sopenharmony_ci dst[3] = cpu_to_le32(sctx->hash[3]); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci ppc_md5_clear_context(sctx); 1048c2ecf20Sopenharmony_ci return 0; 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic int ppc_md5_export(struct shash_desc *desc, void *out) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci struct md5_state *sctx = shash_desc_ctx(desc); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci memcpy(out, sctx, sizeof(*sctx)); 1128c2ecf20Sopenharmony_ci return 0; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic int ppc_md5_import(struct shash_desc *desc, const void *in) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci struct md5_state *sctx = shash_desc_ctx(desc); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci memcpy(sctx, in, sizeof(*sctx)); 1208c2ecf20Sopenharmony_ci return 0; 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic struct shash_alg alg = { 1248c2ecf20Sopenharmony_ci .digestsize = MD5_DIGEST_SIZE, 1258c2ecf20Sopenharmony_ci .init = ppc_md5_init, 1268c2ecf20Sopenharmony_ci .update = ppc_md5_update, 1278c2ecf20Sopenharmony_ci .final = ppc_md5_final, 1288c2ecf20Sopenharmony_ci .export = ppc_md5_export, 1298c2ecf20Sopenharmony_ci .import = ppc_md5_import, 1308c2ecf20Sopenharmony_ci .descsize = sizeof(struct md5_state), 1318c2ecf20Sopenharmony_ci .statesize = sizeof(struct md5_state), 1328c2ecf20Sopenharmony_ci .base = { 1338c2ecf20Sopenharmony_ci .cra_name = "md5", 1348c2ecf20Sopenharmony_ci .cra_driver_name= "md5-ppc", 1358c2ecf20Sopenharmony_ci .cra_priority = 200, 1368c2ecf20Sopenharmony_ci .cra_blocksize = MD5_HMAC_BLOCK_SIZE, 1378c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci}; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic int __init ppc_md5_mod_init(void) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci return crypto_register_shash(&alg); 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic void __exit ppc_md5_mod_fini(void) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci crypto_unregister_shash(&alg); 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cimodule_init(ppc_md5_mod_init); 1528c2ecf20Sopenharmony_cimodule_exit(ppc_md5_mod_fini); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1558c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("MD5 Secure Hash Algorithm, PPC assembler"); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("md5"); 1588c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("md5-ppc"); 159