SHA512.hs (3717B)
1 {-# OPTIONS_HADDOCK prune #-} 2 {-# LANGUAGE BangPatterns #-} 3 4 -- | 5 -- Module: Crypto.Hash.SHA512 6 -- Copyright: (c) 2024 Jared Tobin 7 -- License: MIT 8 -- Maintainer: Jared Tobin <jared@ppad.tech> 9 -- 10 -- SHA-512 and HMAC-SHA512 implementations for 11 -- strict and lazy ByteStrings, as specified by RFC's 12 -- [6234](https://datatracker.ietf.org/doc/html/rfc6234) and 13 -- [2104](https://datatracker.ietf.org/doc/html/rfc2104). 14 -- 15 -- The 'hash' and 'hmac' functions will use primitive instructions from 16 -- the ARM cryptographic extensions via FFI if they're available, and 17 -- will otherwise use a pure Haskell implementation. 18 19 module Crypto.Hash.SHA512 ( 20 -- * SHA-512 message digest functions 21 hash 22 , Lazy.hash_lazy 23 24 -- * SHA512-based MAC functions 25 , MAC(..) 26 , hmac 27 , Lazy.hmac_lazy 28 ) where 29 30 import qualified Data.Bits as B 31 import qualified Data.ByteString as BS 32 import qualified Data.ByteString.Internal as BI 33 import qualified Data.ByteString.Unsafe as BU 34 import Data.Word (Word64) 35 import Crypto.Hash.SHA512.Arm 36 import Crypto.Hash.SHA512.Internal 37 import qualified Crypto.Hash.SHA512.Lazy as Lazy 38 39 -- utils --------------------------------------------------------------------- 40 41 fi :: (Integral a, Num b) => a -> b 42 fi = fromIntegral 43 {-# INLINE fi #-} 44 45 -- hash ---------------------------------------------------------------------- 46 47 -- | Compute a condensed representation of a strict bytestring via 48 -- SHA-512. 49 -- 50 -- The 512-bit output digest is returned as a strict bytestring. 51 -- 52 -- >>> hash "strict bytestring input" 53 -- "<strict 512-bit message digest>" 54 hash :: BS.ByteString -> BS.ByteString 55 hash m 56 | sha512_arm_available = hash_arm m 57 | otherwise = cat (process m) 58 59 -- process a message, given the specified iv 60 process_with :: Registers -> Word64 -> BS.ByteString -> Registers 61 process_with acc0 el m@(BI.PS _ _ l) = finalize (go acc0 0) where 62 go !acc !j 63 | j + 128 <= l = go (block_hash acc (prepare_schedule (parse_block m j))) 64 (j + 128) 65 | otherwise = acc 66 67 finalize !acc 68 | len < 112 = block_hash acc (prepare_schedule (parse_block padded 0)) 69 | otherwise = block_hash 70 (block_hash acc (prepare_schedule (parse_block padded 0))) 71 (prepare_schedule (parse_block padded 128)) 72 where 73 !remaining@(BI.PS _ _ len) = BU.unsafeDrop (l - l `rem` 128) m 74 !padded = unsafe_padding remaining (el + fi l) 75 76 process :: BS.ByteString -> Registers 77 process = process_with iv 0 78 79 -- hmac ---------------------------------------------------------------------- 80 81 data KeyAndLen = KeyAndLen 82 {-# UNPACK #-} !BS.ByteString 83 {-# UNPACK #-} !Int 84 85 -- | Produce a message authentication code for a strict bytestring, 86 -- based on the provided (strict, bytestring) key, via SHA-512. 87 -- 88 -- The 512-bit MAC is returned as a strict bytestring. 89 -- 90 -- Per RFC 2104, the key /should/ be a minimum of 64 bytes long. Keys 91 -- exceeding 128 bytes in length will first be hashed (via SHA-512). 92 -- 93 -- >>> hmac "strict bytestring key" "strict bytestring input" 94 -- "<strict 512-bit MAC>" 95 hmac 96 :: BS.ByteString -- ^ key 97 -> BS.ByteString -- ^ text 98 -> MAC 99 hmac mk@(BI.PS _ _ l) text 100 | sha512_arm_available = 101 let !inner = hash_arm_with ipad 128 text 102 in MAC (hash_arm (opad <> inner)) 103 | otherwise = 104 let !ipad_state = block_hash iv (prepare_schedule (parse_block ipad 0)) 105 !inner = cat (process_with ipad_state 128 text) 106 in MAC (hash (opad <> inner)) 107 where 108 !step1 = k <> BS.replicate (128 - lk) 0x00 109 !ipad = BS.map (B.xor 0x36) step1 110 !opad = BS.map (B.xor 0x5C) step1 111 !(KeyAndLen k lk) 112 | l > 128 = KeyAndLen (hash mk) 64 113 | otherwise = KeyAndLen mk l