-- |
-- Module      : Crypto.PubKey.RSA.PSS
-- License     : BSD-style
-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
-- Stability   : experimental
-- Portability : Good
--
module Crypto.PubKey.RSA.PSS
    ( PSSParams(..)
    , defaultPSSParams
    , defaultPSSParamsSHA1
    -- * Sign and verify functions
    , signWithSalt
    , signDigestWithSalt
    , sign
    , signDigest
    , signSafer
    , signDigestSafer
    , verify
    , verifyDigest
    ) where

import           Crypto.Random.Types
import           Crypto.PubKey.RSA.Types
import           Crypto.PubKey.RSA.Prim
import           Crypto.PubKey.RSA (generateBlinder)
import           Crypto.PubKey.MaskGenFunction
import           Crypto.Hash
import           Crypto.Number.Basic (numBits)
import           Data.Bits (xor, shiftR, (.&.))
import           Data.Word

import           Crypto.Internal.ByteArray (ByteArrayAccess, ByteArray)
import qualified Crypto.Internal.ByteArray as B (convert, eq)

import           Data.ByteString (ByteString)
import qualified Data.ByteString as B

-- | Parameters for PSS signature/verification.
data PSSParams hash seed output = PSSParams
    { forall hash seed output. PSSParams hash seed output -> hash
pssHash         :: hash             -- ^ Hash function to use
    , forall hash seed output.
PSSParams hash seed output -> MaskGenAlgorithm seed output
pssMaskGenAlg   :: MaskGenAlgorithm seed output -- ^ Mask Gen algorithm to use
    , forall hash seed output. PSSParams hash seed output -> Int
pssSaltLength   :: Int              -- ^ Length of salt. need to be <= to hLen.
    , forall hash seed output. PSSParams hash seed output -> Word8
pssTrailerField :: Word8            -- ^ Trailer field, usually 0xbc
    }

-- | Default Params with a specified hash function
defaultPSSParams :: (ByteArrayAccess seed, ByteArray output, HashAlgorithm hash)
                 => hash
                 -> PSSParams hash seed output
defaultPSSParams :: forall seed output hash.
(ByteArrayAccess seed, ByteArray output, HashAlgorithm hash) =>
hash -> PSSParams hash seed output
defaultPSSParams hash
hashAlg =
    PSSParams { pssHash :: hash
pssHash         = hash
hashAlg
              , pssMaskGenAlg :: MaskGenAlgorithm seed output
pssMaskGenAlg   = hash -> MaskGenAlgorithm seed output
forall seed output hashAlg.
(ByteArrayAccess seed, ByteArray output, HashAlgorithm hashAlg) =>
hashAlg -> seed -> Int -> output
mgf1 hash
hashAlg
              , pssSaltLength :: Int
pssSaltLength   = hash -> Int
forall a. HashAlgorithm a => a -> Int
hashDigestSize hash
hashAlg
              , pssTrailerField :: Word8
pssTrailerField = Word8
0xbc
              }

-- | Default Params using SHA1 algorithm.
defaultPSSParamsSHA1 :: PSSParams SHA1 ByteString ByteString
defaultPSSParamsSHA1 :: PSSParams SHA1 ByteString ByteString
defaultPSSParamsSHA1 = SHA1 -> PSSParams SHA1 ByteString ByteString
forall seed output hash.
(ByteArrayAccess seed, ByteArray output, HashAlgorithm hash) =>
hash -> PSSParams hash seed output
defaultPSSParams SHA1
SHA1

-- | Sign using the PSS parameters and the salt explicitely passed as parameters.
--
-- the function ignore SaltLength from the PSS Parameters
signDigestWithSalt :: HashAlgorithm hash
                   => ByteString    -- ^ Salt to use
                   -> Maybe Blinder -- ^ optional blinder to use
                   -> PSSParams hash ByteString ByteString -- ^ PSS Parameters to use
                   -> PrivateKey    -- ^ RSA Private Key
                   -> Digest hash   -- ^ Message digest
                   -> Either Error ByteString
signDigestWithSalt :: forall hash.
HashAlgorithm hash =>
ByteString
-> Maybe Blinder
-> PSSParams hash ByteString ByteString
-> PrivateKey
-> Digest hash
-> Either Error ByteString
signDigestWithSalt ByteString
salt Maybe Blinder
blinder PSSParams hash ByteString ByteString
params PrivateKey
pk Digest hash
digest
    | Int
emLen Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
hashLen Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
saltLen Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2 = Error -> Either Error ByteString
forall a b. a -> Either a b
Left Error
InvalidParameters
    | Bool
otherwise                     = ByteString -> Either Error ByteString
forall a b. b -> Either a b
Right (ByteString -> Either Error ByteString)
-> ByteString -> Either Error ByteString
forall a b. (a -> b) -> a -> b
$ Maybe Blinder -> PrivateKey -> ByteString -> ByteString
forall ba. ByteArray ba => Maybe Blinder -> PrivateKey -> ba -> ba
dp Maybe Blinder
blinder PrivateKey
pk ByteString
em
    where k :: Int
k        = PrivateKey -> Int
private_size PrivateKey
pk
          emLen :: Int
emLen    = if Int -> Bool
emTruncate Int
pubBits then Int
k Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1 else Int
k
          mHash :: ByteString
mHash    = Digest hash -> ByteString
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
B.convert Digest hash
digest
          dbLen :: Int
dbLen    = Int
emLen Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
hashLen Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1
          saltLen :: Int
saltLen  = ByteString -> Int
B.length ByteString
salt
          hashLen :: Int
hashLen  = hash -> Int
forall a. HashAlgorithm a => a -> Int
hashDigestSize (PSSParams hash ByteString ByteString -> hash
forall hash seed output. PSSParams hash seed output -> hash
pssHash PSSParams hash ByteString ByteString
params)
          pubBits :: Int
pubBits  = Integer -> Int
numBits (PrivateKey -> Integer
private_n PrivateKey
pk)
          m' :: ByteString
m'       = [ByteString] -> ByteString
B.concat [Int -> Word8 -> ByteString
B.replicate Int
8 Word8
0,ByteString
mHash,ByteString
salt]
          h :: ByteString
h        = Digest hash -> ByteString
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
B.convert (Digest hash -> ByteString) -> Digest hash -> ByteString
forall a b. (a -> b) -> a -> b
$ hash -> ByteString -> Digest hash
forall ba alg.
(ByteArrayAccess ba, HashAlgorithm alg) =>
alg -> ba -> Digest alg
hashWith (PSSParams hash ByteString ByteString -> hash
forall hash seed output. PSSParams hash seed output -> hash
pssHash PSSParams hash ByteString ByteString
params) ByteString
m'
          db :: ByteString
db       = [ByteString] -> ByteString
B.concat [Int -> Word8 -> ByteString
B.replicate (Int
dbLen Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
saltLen Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Word8
0,Word8 -> ByteString
B.singleton Word8
1,ByteString
salt]
          dbmask :: ByteString
dbmask   = PSSParams hash ByteString ByteString
-> MaskGenAlgorithm ByteString ByteString
forall hash seed output.
PSSParams hash seed output -> MaskGenAlgorithm seed output
pssMaskGenAlg PSSParams hash ByteString ByteString
params ByteString
h Int
dbLen
          maskedDB :: ByteString
maskedDB = [Word8] -> ByteString
B.pack ([Word8] -> ByteString) -> [Word8] -> ByteString
forall a b. (a -> b) -> a -> b
$ Int -> [Word8] -> [Word8]
normalizeToKeySize Int
pubBits ([Word8] -> [Word8]) -> [Word8] -> [Word8]
forall a b. (a -> b) -> a -> b
$ (Word8 -> Word8 -> Word8) -> ByteString -> ByteString -> [Word8]
forall a. (Word8 -> Word8 -> a) -> ByteString -> ByteString -> [a]
B.zipWith Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
xor ByteString
db ByteString
dbmask
          em :: ByteString
em       = [ByteString] -> ByteString
B.concat [ByteString
maskedDB, ByteString
h, Word8 -> ByteString
B.singleton (PSSParams hash ByteString ByteString -> Word8
forall hash seed output. PSSParams hash seed output -> Word8
pssTrailerField PSSParams hash ByteString ByteString
params)]

-- | Sign using the PSS parameters and the salt explicitely passed as parameters.
--
-- the function ignore SaltLength from the PSS Parameters
signWithSalt :: HashAlgorithm hash
             => ByteString    -- ^ Salt to use
             -> Maybe Blinder -- ^ optional blinder to use
             -> PSSParams hash ByteString ByteString -- ^ PSS Parameters to use
             -> PrivateKey    -- ^ RSA Private Key
             -> ByteString    -- ^ Message to sign
             -> Either Error ByteString
signWithSalt :: forall hash.
HashAlgorithm hash =>
ByteString
-> Maybe Blinder
-> PSSParams hash ByteString ByteString
-> PrivateKey
-> ByteString
-> Either Error ByteString
signWithSalt ByteString
salt Maybe Blinder
blinder PSSParams hash ByteString ByteString
params PrivateKey
pk ByteString
m = ByteString
-> Maybe Blinder
-> PSSParams hash ByteString ByteString
-> PrivateKey
-> Digest hash
-> Either Error ByteString
forall hash.
HashAlgorithm hash =>
ByteString
-> Maybe Blinder
-> PSSParams hash ByteString ByteString
-> PrivateKey
-> Digest hash
-> Either Error ByteString
signDigestWithSalt ByteString
salt Maybe Blinder
blinder PSSParams hash ByteString ByteString
params PrivateKey
pk Digest hash
mHash
    where mHash :: Digest hash
mHash    = hash -> ByteString -> Digest hash
forall ba alg.
(ByteArrayAccess ba, HashAlgorithm alg) =>
alg -> ba -> Digest alg
hashWith (PSSParams hash ByteString ByteString -> hash
forall hash seed output. PSSParams hash seed output -> hash
pssHash PSSParams hash ByteString ByteString
params) ByteString
m

-- | Sign using the PSS Parameters
sign :: (HashAlgorithm hash, MonadRandom m)
     => Maybe Blinder   -- ^ optional blinder to use
     -> PSSParams hash ByteString ByteString -- ^ PSS Parameters to use
     -> PrivateKey      -- ^ RSA Private Key
     -> ByteString      -- ^ Message to sign
     -> m (Either Error ByteString)
sign :: forall hash (m :: * -> *).
(HashAlgorithm hash, MonadRandom m) =>
Maybe Blinder
-> PSSParams hash ByteString ByteString
-> PrivateKey
-> ByteString
-> m (Either Error ByteString)
sign Maybe Blinder
blinder PSSParams hash ByteString ByteString
params PrivateKey
pk ByteString
m = do
    ByteString
salt <- Int -> m ByteString
forall byteArray. ByteArray byteArray => Int -> m byteArray
forall (m :: * -> *) byteArray.
(MonadRandom m, ByteArray byteArray) =>
Int -> m byteArray
getRandomBytes (PSSParams hash ByteString ByteString -> Int
forall hash seed output. PSSParams hash seed output -> Int
pssSaltLength PSSParams hash ByteString ByteString
params)
    Either Error ByteString -> m (Either Error ByteString)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (ByteString
-> Maybe Blinder
-> PSSParams hash ByteString ByteString
-> PrivateKey
-> ByteString
-> Either Error ByteString
forall hash.
HashAlgorithm hash =>
ByteString
-> Maybe Blinder
-> PSSParams hash ByteString ByteString
-> PrivateKey
-> ByteString
-> Either Error ByteString
signWithSalt ByteString
salt Maybe Blinder
blinder PSSParams hash ByteString ByteString
params PrivateKey
pk ByteString
m)

-- | Sign using the PSS Parameters
signDigest :: (HashAlgorithm hash, MonadRandom m)
           => Maybe Blinder   -- ^ optional blinder to use
           -> PSSParams hash ByteString ByteString -- ^ PSS Parameters to use
           -> PrivateKey      -- ^ RSA Private Key
           -> Digest hash     -- ^ Message digest
           -> m (Either Error ByteString)
signDigest :: forall hash (m :: * -> *).
(HashAlgorithm hash, MonadRandom m) =>
Maybe Blinder
-> PSSParams hash ByteString ByteString
-> PrivateKey
-> Digest hash
-> m (Either Error ByteString)
signDigest Maybe Blinder
blinder PSSParams hash ByteString ByteString
params PrivateKey
pk Digest hash
digest = do
    ByteString
salt <- Int -> m ByteString
forall byteArray. ByteArray byteArray => Int -> m byteArray
forall (m :: * -> *) byteArray.
(MonadRandom m, ByteArray byteArray) =>
Int -> m byteArray
getRandomBytes (PSSParams hash ByteString ByteString -> Int
forall hash seed output. PSSParams hash seed output -> Int
pssSaltLength PSSParams hash ByteString ByteString
params)
    Either Error ByteString -> m (Either Error ByteString)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (ByteString
-> Maybe Blinder
-> PSSParams hash ByteString ByteString
-> PrivateKey
-> Digest hash
-> Either Error ByteString
forall hash.
HashAlgorithm hash =>
ByteString
-> Maybe Blinder
-> PSSParams hash ByteString ByteString
-> PrivateKey
-> Digest hash
-> Either Error ByteString
signDigestWithSalt ByteString
salt Maybe Blinder
blinder PSSParams hash ByteString ByteString
params PrivateKey
pk Digest hash
digest)

-- | Sign using the PSS Parameters and an automatically generated blinder.
signSafer :: (HashAlgorithm hash, MonadRandom m)
          => PSSParams hash ByteString ByteString -- ^ PSS Parameters to use
          -> PrivateKey     -- ^ private key
          -> ByteString     -- ^ message to sign
          -> m (Either Error ByteString)
signSafer :: forall hash (m :: * -> *).
(HashAlgorithm hash, MonadRandom m) =>
PSSParams hash ByteString ByteString
-> PrivateKey -> ByteString -> m (Either Error ByteString)
signSafer PSSParams hash ByteString ByteString
params PrivateKey
pk ByteString
m = do
    Blinder
blinder <- Integer -> m Blinder
forall (m :: * -> *). MonadRandom m => Integer -> m Blinder
generateBlinder (PrivateKey -> Integer
private_n PrivateKey
pk)
    Maybe Blinder
-> PSSParams hash ByteString ByteString
-> PrivateKey
-> ByteString
-> m (Either Error ByteString)
forall hash (m :: * -> *).
(HashAlgorithm hash, MonadRandom m) =>
Maybe Blinder
-> PSSParams hash ByteString ByteString
-> PrivateKey
-> ByteString
-> m (Either Error ByteString)
sign (Blinder -> Maybe Blinder
forall a. a -> Maybe a
Just Blinder
blinder) PSSParams hash ByteString ByteString
params PrivateKey
pk ByteString
m

-- | Sign using the PSS Parameters and an automatically generated blinder.
signDigestSafer :: (HashAlgorithm hash, MonadRandom m)
                => PSSParams hash ByteString ByteString -- ^ PSS Parameters to use
                -> PrivateKey     -- ^ private key
                -> Digest hash    -- ^ message digst
                -> m (Either Error ByteString)
signDigestSafer :: forall hash (m :: * -> *).
(HashAlgorithm hash, MonadRandom m) =>
PSSParams hash ByteString ByteString
-> PrivateKey -> Digest hash -> m (Either Error ByteString)
signDigestSafer PSSParams hash ByteString ByteString
params PrivateKey
pk Digest hash
digest = do
    Blinder
blinder <- Integer -> m Blinder
forall (m :: * -> *). MonadRandom m => Integer -> m Blinder
generateBlinder (PrivateKey -> Integer
private_n PrivateKey
pk)
    Maybe Blinder
-> PSSParams hash ByteString ByteString
-> PrivateKey
-> Digest hash
-> m (Either Error ByteString)
forall hash (m :: * -> *).
(HashAlgorithm hash, MonadRandom m) =>
Maybe Blinder
-> PSSParams hash ByteString ByteString
-> PrivateKey
-> Digest hash
-> m (Either Error ByteString)
signDigest (Blinder -> Maybe Blinder
forall a. a -> Maybe a
Just Blinder
blinder) PSSParams hash ByteString ByteString
params PrivateKey
pk Digest hash
digest

-- | Verify a signature using the PSS Parameters
verify :: HashAlgorithm hash
       => PSSParams hash ByteString ByteString
                     -- ^ PSS Parameters to use to verify,
                     --   this need to be identical to the parameters when signing
       -> PublicKey  -- ^ RSA Public Key
       -> ByteString -- ^ Message to verify
       -> ByteString -- ^ Signature
       -> Bool
verify :: forall hash.
HashAlgorithm hash =>
PSSParams hash ByteString ByteString
-> PublicKey -> ByteString -> ByteString -> Bool
verify PSSParams hash ByteString ByteString
params PublicKey
pk ByteString
m = PSSParams hash ByteString ByteString
-> PublicKey -> Digest hash -> ByteString -> Bool
forall hash.
HashAlgorithm hash =>
PSSParams hash ByteString ByteString
-> PublicKey -> Digest hash -> ByteString -> Bool
verifyDigest PSSParams hash ByteString ByteString
params PublicKey
pk Digest hash
mHash
  where mHash :: Digest hash
mHash     = hash -> ByteString -> Digest hash
forall ba alg.
(ByteArrayAccess ba, HashAlgorithm alg) =>
alg -> ba -> Digest alg
hashWith (PSSParams hash ByteString ByteString -> hash
forall hash seed output. PSSParams hash seed output -> hash
pssHash PSSParams hash ByteString ByteString
params) ByteString
m

-- | Verify a signature using the PSS Parameters
verifyDigest :: HashAlgorithm hash
             => PSSParams hash ByteString ByteString
                            -- ^ PSS Parameters to use to verify,
                            --   this need to be identical to the parameters when signing
             -> PublicKey   -- ^ RSA Public Key
             -> Digest hash -- ^ Digest to verify
             -> ByteString  -- ^ Signature
             -> Bool
verifyDigest :: forall hash.
HashAlgorithm hash =>
PSSParams hash ByteString ByteString
-> PublicKey -> Digest hash -> ByteString -> Bool
verifyDigest PSSParams hash ByteString ByteString
params PublicKey
pk Digest hash
digest ByteString
s
    | ByteString -> Int
B.length ByteString
s Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
k                     = Bool
False
    | (Word8 -> Bool) -> ByteString -> Bool
B.any (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word8
0) ByteString
pre                    = Bool
False
    | HasCallStack => ByteString -> Word8
ByteString -> Word8
B.last ByteString
em Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
/= PSSParams hash ByteString ByteString -> Word8
forall hash seed output. PSSParams hash seed output -> Word8
pssTrailerField PSSParams hash ByteString ByteString
params = Bool
False
    | (Word8 -> Bool) -> ByteString -> Bool
B.any (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word8
0) ByteString
ps0                    = Bool
False
    | ByteString
b1 ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
/= Word8 -> ByteString
B.singleton Word8
1                 = Bool
False
    | Bool
otherwise                           = ByteString -> Digest hash -> Bool
forall bs1 bs2.
(ByteArrayAccess bs1, ByteArrayAccess bs2) =>
bs1 -> bs2 -> Bool
B.eq ByteString
h Digest hash
h'
        where -- parameters
              hashLen :: Int
hashLen   = hash -> Int
forall a. HashAlgorithm a => a -> Int
hashDigestSize (PSSParams hash ByteString ByteString -> hash
forall hash seed output. PSSParams hash seed output -> hash
pssHash PSSParams hash ByteString ByteString
params)
              mHash :: ByteString
mHash     = Digest hash -> ByteString
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
B.convert Digest hash
digest
              k :: Int
k         = PublicKey -> Int
public_size PublicKey
pk
              emLen :: Int
emLen     = if Int -> Bool
emTruncate Int
pubBits then Int
k Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1 else Int
k
              dbLen :: Int
dbLen     = Int
emLen Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
hashLen Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1
              pubBits :: Int
pubBits   = Integer -> Int
numBits (PublicKey -> Integer
public_n PublicKey
pk)
              -- unmarshall fields
              (ByteString
pre, ByteString
em) = Int -> ByteString -> (ByteString, ByteString)
B.splitAt (Int
k Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
emLen) (PublicKey -> ByteString -> ByteString
forall ba. ByteArray ba => PublicKey -> ba -> ba
ep PublicKey
pk ByteString
s) -- drop 0..1 byte
              maskedDB :: ByteString
maskedDB  = Int -> ByteString -> ByteString
B.take Int
dbLen ByteString
em
              h :: ByteString
h         = Int -> ByteString -> ByteString
B.take Int
hashLen (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ Int -> ByteString -> ByteString
B.drop (ByteString -> Int
B.length ByteString
maskedDB) ByteString
em
              dbmask :: ByteString
dbmask    = PSSParams hash ByteString ByteString
-> MaskGenAlgorithm ByteString ByteString
forall hash seed output.
PSSParams hash seed output -> MaskGenAlgorithm seed output
pssMaskGenAlg PSSParams hash ByteString ByteString
params ByteString
h Int
dbLen
              db :: ByteString
db        = [Word8] -> ByteString
B.pack ([Word8] -> ByteString) -> [Word8] -> ByteString
forall a b. (a -> b) -> a -> b
$ Int -> [Word8] -> [Word8]
normalizeToKeySize Int
pubBits ([Word8] -> [Word8]) -> [Word8] -> [Word8]
forall a b. (a -> b) -> a -> b
$ (Word8 -> Word8 -> Word8) -> ByteString -> ByteString -> [Word8]
forall a. (Word8 -> Word8 -> a) -> ByteString -> ByteString -> [a]
B.zipWith Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
xor ByteString
maskedDB ByteString
dbmask
              (ByteString
ps0,ByteString
z)   = (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
B.break (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
1) ByteString
db
              (ByteString
b1,ByteString
salt) = Int -> ByteString -> (ByteString, ByteString)
B.splitAt Int
1 ByteString
z
              m' :: ByteString
m'        = [ByteString] -> ByteString
B.concat [Int -> Word8 -> ByteString
B.replicate Int
8 Word8
0,ByteString
mHash,ByteString
salt]
              h' :: Digest hash
h'        = hash -> ByteString -> Digest hash
forall ba alg.
(ByteArrayAccess ba, HashAlgorithm alg) =>
alg -> ba -> Digest alg
hashWith (PSSParams hash ByteString ByteString -> hash
forall hash seed output. PSSParams hash seed output -> hash
pssHash PSSParams hash ByteString ByteString
params) ByteString
m'

-- When the modulus has bit length 1 modulo 8 we drop the first byte.
emTruncate :: Int -> Bool
emTruncate :: Int -> Bool
emTruncate Int
bits = ((Int
bitsInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1) Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
0x7) Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0

normalizeToKeySize :: Int -> [Word8] -> [Word8]
normalizeToKeySize :: Int -> [Word8] -> [Word8]
normalizeToKeySize Int
_    []     = [] -- very unlikely
normalizeToKeySize Int
bits (Word8
x:[Word8]
xs) = Word8
x Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
mask Word8 -> [Word8] -> [Word8]
forall a. a -> [a] -> [a]
: [Word8]
xs
    where mask :: Word8
mask = if Int
sh Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0 then Word8
0xff Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`shiftR` (Int
8Int -> Int -> Int
forall a. Num a => a -> a -> a
-Int
sh) else Word8
0xff
          sh :: Int
sh   = (Int
bitsInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1) Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
0x7