cryptostore-0.5.0.0: src/Crypto/Store/KeyWrap/TripleDES.hs
-- |
-- Module : Crypto.Store.KeyWrap.TripleDES
-- License : BSD-style
-- Maintainer : Olivier Chéron <olivier.cheron@gmail.com>
-- Stability : experimental
-- Portability : unknown
--
-- Triple-DES Key Wrap (<https://tools.ietf.org/html/rfc3217 RFC 3217>)
--
-- Should be used with a cipher from module "Crypto.Cipher.TripleDES".
module Crypto.Store.KeyWrap.TripleDES
( wrap
, unwrap
) where
import Data.ByteArray (ByteArray)
import qualified Data.ByteArray as B
import Data.Maybe (fromJust)
import Crypto.Cipher.Types
import Crypto.Hash
import Crypto.Store.Error
import Crypto.Store.Util
checksum :: ByteArray ba => ba -> ba
checksum bs = B.convert $ B.takeView (hashWith SHA1 bs) 8
iv4adda22c79e82105 :: B.Bytes
iv4adda22c79e82105 = B.pack [0x4a, 0xdd, 0xa2, 0x2c, 0x79, 0xe8, 0x21, 0x05]
-- | Wrap a Triple-DES key with the specified Triple-DES cipher.
--
-- Input must be 24 bytes. A fresh IV should be generated randomly for each
-- invocation.
wrap :: (BlockCipher cipher, ByteArray ba)
=> cipher -> IV cipher -> ba -> Either StoreError ba
wrap cipher iv cek
| inLen == 24 = Right wrapped
| otherwise = Left
(InvalidInput "KeyWrap.TripleDES: invalid length for content encryption key")
where
inLen = B.length cek
iv' = fromJust $ makeIV iv4adda22c79e82105
cekicv = B.append cek (checksum cek)
temp1 = cbcEncrypt cipher iv cekicv
temp2 = B.append (B.convert iv) temp1
temp3 = reverseBytes temp2
wrapped = cbcEncrypt cipher iv' temp3
-- | Unwrap an encrypted Triple-DES key with the specified Triple-DES cipher.
unwrap :: (BlockCipher cipher, ByteArray ba)
=> cipher -> ba -> Either StoreError ba
unwrap cipher wrapped
| inLen /= 40 = invalid
| B.constEq icv (checksum cek) = Right cek
| otherwise = invalid
where
inLen = B.length wrapped
iv' = fromJust $ makeIV iv4adda22c79e82105
temp3 = cbcDecrypt cipher iv' wrapped
temp2 = reverseBytes temp3
(ivBs, temp1) = B.splitAt 8 temp2
iv = fromJust $ makeIV ivBs
cekicv = cbcDecrypt cipher iv temp1
(cek, icv) = B.splitAt 24 cekicv
invalid = Left BadChecksum