1 /* Copyright (c) 2023, Google Inc. 2 * 3 * Permission to use, copy, modify, and/or distribute this software for any 4 * purpose with or without fee is hereby granted, provided that the above 5 * copyright notice and this permission notice appear in all copies. 6 * 7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 */ 15 16 //! Hash functions. 17 //! 18 //! ``` 19 //! use bssl_crypto::digest; 20 //! 21 //! // One-shot hashing. 22 //! let digest: [u8; 32] = digest::Sha256::hash(b"hello"); 23 //! 24 //! // Incremental hashing. 25 //! let mut ctx = digest::Sha256::new(); 26 //! ctx.update(b"hel"); 27 //! ctx.update(b"lo"); 28 //! let digest2: [u8; 32] = ctx.digest(); 29 //! 30 //! assert_eq!(digest, digest2); 31 //! ``` 32 33 use crate::{sealed, FfiSlice, ForeignTypeRef}; 34 use alloc::vec::Vec; 35 36 #[non_exhaustive] 37 #[doc(hidden)] 38 pub struct MdRef; 39 40 unsafe impl ForeignTypeRef for MdRef { 41 type CType = bssl_sys::EVP_MD; 42 } 43 44 /// Provides the ability to hash in an algorithm-agnostic manner. 45 pub trait Algorithm { 46 /// The size of the resulting digest. 47 const OUTPUT_LEN: usize; 48 /// The block length (in bytes). 49 const BLOCK_LEN: usize; 50 51 /// Gets a reference to a message digest algorithm to be used by the HKDF implementation. 52 #[doc(hidden)] get_md(_: sealed::Sealed) -> &'static MdRef53 fn get_md(_: sealed::Sealed) -> &'static MdRef; 54 55 /// Hashes a message. hash_to_vec(input: &[u8]) -> Vec<u8>56 fn hash_to_vec(input: &[u8]) -> Vec<u8>; 57 58 /// Create a new context for incremental hashing. new() -> Self59 fn new() -> Self; 60 61 /// Hash the contents of `input`. update(&mut self, input: &[u8])62 fn update(&mut self, input: &[u8]); 63 64 /// Finish the hashing and return the digest. digest_to_vec(self) -> Vec<u8>65 fn digest_to_vec(self) -> Vec<u8>; 66 } 67 68 /// The insecure SHA-1 hash algorithm. 69 /// 70 /// Some existing protocols depend on SHA-1 and so it is provided here, but it 71 /// does not provide collision resistance and should not be used if at all 72 /// avoidable. Use SHA-256 instead. 73 #[derive(Clone)] 74 pub struct InsecureSha1 { 75 ctx: bssl_sys::SHA_CTX, 76 } 77 78 unsafe_iuf_algo!( 79 InsecureSha1, 80 20, 81 64, 82 EVP_sha1, 83 SHA1, 84 SHA1_Init, 85 SHA1_Update, 86 SHA1_Final 87 ); 88 89 /// The SHA-256 hash algorithm. 90 #[derive(Clone)] 91 pub struct Sha256 { 92 ctx: bssl_sys::SHA256_CTX, 93 } 94 95 unsafe_iuf_algo!( 96 Sha256, 97 32, 98 64, 99 EVP_sha256, 100 SHA256, 101 SHA256_Init, 102 SHA256_Update, 103 SHA256_Final 104 ); 105 106 /// The SHA-384 hash algorithm. 107 #[derive(Clone)] 108 pub struct Sha384 { 109 ctx: bssl_sys::SHA512_CTX, 110 } 111 112 unsafe_iuf_algo!( 113 Sha384, 114 48, 115 128, 116 EVP_sha384, 117 SHA384, 118 SHA384_Init, 119 SHA384_Update, 120 SHA384_Final 121 ); 122 123 /// The SHA-512 hash algorithm. 124 #[derive(Clone)] 125 pub struct Sha512 { 126 ctx: bssl_sys::SHA512_CTX, 127 } 128 129 unsafe_iuf_algo!( 130 Sha512, 131 64, 132 128, 133 EVP_sha512, 134 SHA512, 135 SHA512_Init, 136 SHA512_Update, 137 SHA512_Final 138 ); 139 140 /// The SHA-512/256 hash algorithm. 141 #[derive(Clone)] 142 pub struct Sha512_256 { 143 ctx: bssl_sys::SHA512_CTX, 144 } 145 146 unsafe_iuf_algo!( 147 Sha512_256, 148 32, 149 128, 150 EVP_sha512_256, 151 SHA512_256, 152 SHA512_256_Init, 153 SHA512_256_Update, 154 SHA512_256_Final 155 ); 156 157 #[cfg(test)] 158 mod test { 159 use super::*; 160 use crate::test_helpers::decode_hex; 161 162 #[test] sha256_c_type()163 fn sha256_c_type() { 164 unsafe { 165 assert_eq!( 166 MdRef::from_ptr(bssl_sys::EVP_sha256() as *mut _).as_ptr(), 167 bssl_sys::EVP_sha256() as *mut _ 168 ) 169 } 170 } 171 172 #[test] sha512_c_type()173 fn sha512_c_type() { 174 unsafe { 175 assert_eq!( 176 MdRef::from_ptr(bssl_sys::EVP_sha512() as *mut _).as_ptr(), 177 bssl_sys::EVP_sha512() as *mut _ 178 ) 179 } 180 } 181 182 #[test] sha1()183 fn sha1() { 184 assert_eq!( 185 decode_hex("a9993e364706816aba3e25717850c26c9cd0d89d"), 186 InsecureSha1::hash(b"abc") 187 ); 188 } 189 190 #[test] sha256()191 fn sha256() { 192 let msg: [u8; 4] = decode_hex("74ba2521"); 193 let expected_digest: [u8; 32] = 194 decode_hex("b16aa56be3880d18cd41e68384cf1ec8c17680c45a02b1575dc1518923ae8b0e"); 195 196 assert_eq!(Sha256::hash(&msg), expected_digest); 197 198 let mut ctx = Sha256::new(); 199 ctx.update(&msg); 200 assert_eq!(expected_digest, ctx.digest()); 201 202 let mut ctx = Sha256::new(); 203 ctx.update(&msg[0..1]); 204 let mut ctx2 = ctx.clone(); 205 ctx2.update(&msg[1..]); 206 assert_eq!(expected_digest, ctx2.digest()); 207 } 208 209 #[test] sha384()210 fn sha384() { 211 assert_eq!( 212 decode_hex("cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7"), 213 Sha384::hash(b"abc") 214 ); 215 } 216 217 #[test] sha512()218 fn sha512() { 219 let msg: [u8; 4] = decode_hex("23be86d5"); 220 let expected_digest: [u8; 64] = decode_hex(concat!( 221 "76d42c8eadea35a69990c63a762f330614a4699977f058adb988f406fb0be8f2", 222 "ea3dce3a2bbd1d827b70b9b299ae6f9e5058ee97b50bd4922d6d37ddc761f8eb" 223 )); 224 225 assert_eq!(Sha512::hash(&msg), expected_digest); 226 227 let mut ctx = Sha512::new(); 228 ctx.update(&msg); 229 assert_eq!(expected_digest, ctx.digest()); 230 } 231 232 #[test] sha512_256()233 fn sha512_256() { 234 assert_eq!( 235 decode_hex("53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23"), 236 Sha512_256::hash(b"abc") 237 ); 238 } 239 } 240