automotive-cse 0.1.2.0 → 0.1.3.0
raw patch · 3 files changed
+302/−283 lines, 3 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- Codec.Automotive.CSE: data Auth
- Codec.Automotive.CSE: data Derived k c
- Codec.Automotive.CSE: data DerivedCipher k c
- Codec.Automotive.CSE: data Enc
- Codec.Automotive.CSE: data KeyAuthUse k
- Codec.Automotive.CSE: data M1
- Codec.Automotive.CSE: data M2
- Codec.Automotive.CSE: data M3
- Codec.Automotive.CSE: data M4
- Codec.Automotive.CSE: data M5
- Codec.Automotive.CSE: data Mac
- Codec.Automotive.CSE: data NotAuth
- Codec.Automotive.CSE: data UID
- Codec.Automotive.CSE: data UpdateC c
- Codec.Automotive.CSE: derivedCipher :: Derived k c -> DerivedCipher k c
- Codec.Automotive.CSE: extractM1 :: M1 -> (UID, Word8, Word8)
- Codec.Automotive.CSE: extractM4 :: K3 -> M4 -> ((UID, Word8, Word8), Word32)
- Codec.Automotive.CSE: extractM4' :: K3 -> M4 -> (M1, Word32)
- Codec.Automotive.CSE: instance GHC.Classes.Eq (Codec.Automotive.CSE.Derived k c)
- Codec.Automotive.CSE: instance GHC.Classes.Eq (Codec.Automotive.CSE.KeyAuthUse k)
- Codec.Automotive.CSE: instance GHC.Classes.Eq (Codec.Automotive.CSE.UpdateC c)
- Codec.Automotive.CSE: instance GHC.Classes.Eq Codec.Automotive.CSE.M1
- Codec.Automotive.CSE: instance GHC.Classes.Eq Codec.Automotive.CSE.M2
- Codec.Automotive.CSE: instance GHC.Classes.Eq Codec.Automotive.CSE.M3
- Codec.Automotive.CSE: instance GHC.Classes.Eq Codec.Automotive.CSE.M4
- Codec.Automotive.CSE: instance GHC.Classes.Eq Codec.Automotive.CSE.M5
- Codec.Automotive.CSE: instance GHC.Classes.Eq Codec.Automotive.CSE.UID
- Codec.Automotive.CSE: instance GHC.Classes.Ord Codec.Automotive.CSE.UID
- Codec.Automotive.CSE: instance GHC.Show.Show (Codec.Automotive.CSE.Derived k c)
- Codec.Automotive.CSE: instance GHC.Show.Show (Codec.Automotive.CSE.UpdateC c)
- Codec.Automotive.CSE: instance GHC.Show.Show Codec.Automotive.CSE.M1
- Codec.Automotive.CSE: instance GHC.Show.Show Codec.Automotive.CSE.M2
- Codec.Automotive.CSE: instance GHC.Show.Show Codec.Automotive.CSE.M3
- Codec.Automotive.CSE: instance GHC.Show.Show Codec.Automotive.CSE.M4
- Codec.Automotive.CSE: instance GHC.Show.Show Codec.Automotive.CSE.M5
- Codec.Automotive.CSE: instance GHC.Show.Show Codec.Automotive.CSE.UID
- Codec.Automotive.CSE: kdf :: KeyAuthUse k -> UpdateC c -> Derived k c
- Codec.Automotive.CSE: keyUpdateEncC :: UpdateC Enc
- Codec.Automotive.CSE: keyUpdateMacC :: UpdateC Mac
- Codec.Automotive.CSE: makeK1 :: KeyAuthUse Auth -> K1'
- Codec.Automotive.CSE: makeK2 :: KeyAuthUse Auth -> K2'
- Codec.Automotive.CSE: makeK3 :: KeyAuthUse NotAuth -> K3'
- Codec.Automotive.CSE: makeK4 :: KeyAuthUse NotAuth -> K4'
- Codec.Automotive.CSE: makeKeyAuthUse :: MonadPlus m => ByteString -> m (KeyAuthUse k)
- Codec.Automotive.CSE: makeM1 :: UID -> Word8 -> Word8 -> M1
- Codec.Automotive.CSE: makeM2 :: K1 -> Word32 -> Word8 -> KeyAuthUse NotAuth -> M2
- Codec.Automotive.CSE: makeM3 :: K2 -> M1 -> M2 -> M3
- Codec.Automotive.CSE: makeM4 :: K3 -> UID -> Word8 -> Word8 -> Word32 -> M4
- Codec.Automotive.CSE: makeM4' :: K3 -> M1 -> Word32 -> M4
- Codec.Automotive.CSE: makeM5 :: K4 -> M4 -> M5
- Codec.Automotive.CSE: makeUID :: MonadPlus m => ByteString -> m UID
- Codec.Automotive.CSE: type K1 = DerivedCipher Auth Enc
- Codec.Automotive.CSE: type K1' = Derived Auth Enc
- Codec.Automotive.CSE: type K2 = DerivedCipher Auth Mac
- Codec.Automotive.CSE: type K2' = Derived Auth Mac
- Codec.Automotive.CSE: type K3 = DerivedCipher NotAuth Enc
- Codec.Automotive.CSE: type K3' = Derived NotAuth Enc
- Codec.Automotive.CSE: type K4 = DerivedCipher NotAuth Mac
- Codec.Automotive.CSE: type K4' = Derived NotAuth Mac
- Codec.Automotive.CSE: unDerived :: Derived k c -> ByteString
- Codec.Automotive.CSE: unKeyAuthUse :: KeyAuthUse k -> ByteString
- Codec.Automotive.CSE: unM1 :: M1 -> ByteString
- Codec.Automotive.CSE: unM2 :: M2 -> ByteString
- Codec.Automotive.CSE: unM3 :: M3 -> ByteString
- Codec.Automotive.CSE: unM4 :: M4 -> ByteString
- Codec.Automotive.CSE: unM5 :: M5 -> ByteString
- Codec.Automotive.CSE: unUID :: UID -> ByteString
+ Codec.Automotive.CSE.Internal: data Auth
+ Codec.Automotive.CSE.Internal: data Derived k c
+ Codec.Automotive.CSE.Internal: data DerivedCipher k c
+ Codec.Automotive.CSE.Internal: data Enc
+ Codec.Automotive.CSE.Internal: data KeyAuthUse k
+ Codec.Automotive.CSE.Internal: data M1
+ Codec.Automotive.CSE.Internal: data M2
+ Codec.Automotive.CSE.Internal: data M3
+ Codec.Automotive.CSE.Internal: data M4
+ Codec.Automotive.CSE.Internal: data M5
+ Codec.Automotive.CSE.Internal: data Mac
+ Codec.Automotive.CSE.Internal: data NotAuth
+ Codec.Automotive.CSE.Internal: data UID
+ Codec.Automotive.CSE.Internal: data UpdateC c
+ Codec.Automotive.CSE.Internal: derivedCipher :: Derived k c -> DerivedCipher k c
+ Codec.Automotive.CSE.Internal: extractM1 :: M1 -> (UID, Word8, Word8)
+ Codec.Automotive.CSE.Internal: extractM4 :: K3 -> M4 -> ((UID, Word8, Word8), Word32)
+ Codec.Automotive.CSE.Internal: extractM4' :: K3 -> M4 -> (M1, Word32)
+ Codec.Automotive.CSE.Internal: instance GHC.Classes.Eq (Codec.Automotive.CSE.Internal.Derived k c)
+ Codec.Automotive.CSE.Internal: instance GHC.Classes.Eq (Codec.Automotive.CSE.Internal.KeyAuthUse k)
+ Codec.Automotive.CSE.Internal: instance GHC.Classes.Eq (Codec.Automotive.CSE.Internal.UpdateC c)
+ Codec.Automotive.CSE.Internal: instance GHC.Classes.Eq Codec.Automotive.CSE.Internal.M1
+ Codec.Automotive.CSE.Internal: instance GHC.Classes.Eq Codec.Automotive.CSE.Internal.M2
+ Codec.Automotive.CSE.Internal: instance GHC.Classes.Eq Codec.Automotive.CSE.Internal.M3
+ Codec.Automotive.CSE.Internal: instance GHC.Classes.Eq Codec.Automotive.CSE.Internal.M4
+ Codec.Automotive.CSE.Internal: instance GHC.Classes.Eq Codec.Automotive.CSE.Internal.M5
+ Codec.Automotive.CSE.Internal: instance GHC.Classes.Eq Codec.Automotive.CSE.Internal.UID
+ Codec.Automotive.CSE.Internal: instance GHC.Classes.Ord Codec.Automotive.CSE.Internal.UID
+ Codec.Automotive.CSE.Internal: instance GHC.Show.Show (Codec.Automotive.CSE.Internal.Derived k c)
+ Codec.Automotive.CSE.Internal: instance GHC.Show.Show (Codec.Automotive.CSE.Internal.UpdateC c)
+ Codec.Automotive.CSE.Internal: instance GHC.Show.Show Codec.Automotive.CSE.Internal.M1
+ Codec.Automotive.CSE.Internal: instance GHC.Show.Show Codec.Automotive.CSE.Internal.M2
+ Codec.Automotive.CSE.Internal: instance GHC.Show.Show Codec.Automotive.CSE.Internal.M3
+ Codec.Automotive.CSE.Internal: instance GHC.Show.Show Codec.Automotive.CSE.Internal.M4
+ Codec.Automotive.CSE.Internal: instance GHC.Show.Show Codec.Automotive.CSE.Internal.M5
+ Codec.Automotive.CSE.Internal: instance GHC.Show.Show Codec.Automotive.CSE.Internal.UID
+ Codec.Automotive.CSE.Internal: kdf :: KeyAuthUse k -> UpdateC c -> Derived k c
+ Codec.Automotive.CSE.Internal: keyUpdateEncC :: UpdateC Enc
+ Codec.Automotive.CSE.Internal: keyUpdateMacC :: UpdateC Mac
+ Codec.Automotive.CSE.Internal: makeK1 :: KeyAuthUse Auth -> K1'
+ Codec.Automotive.CSE.Internal: makeK2 :: KeyAuthUse Auth -> K2'
+ Codec.Automotive.CSE.Internal: makeK3 :: KeyAuthUse NotAuth -> K3'
+ Codec.Automotive.CSE.Internal: makeK4 :: KeyAuthUse NotAuth -> K4'
+ Codec.Automotive.CSE.Internal: makeKeyAuthUse :: MonadPlus m => ByteString -> m (KeyAuthUse k)
+ Codec.Automotive.CSE.Internal: makeM1 :: UID -> Word8 -> Word8 -> M1
+ Codec.Automotive.CSE.Internal: makeM2 :: K1 -> Word32 -> Word8 -> KeyAuthUse NotAuth -> M2
+ Codec.Automotive.CSE.Internal: makeM3 :: K2 -> M1 -> M2 -> M3
+ Codec.Automotive.CSE.Internal: makeM4 :: K3 -> UID -> Word8 -> Word8 -> Word32 -> M4
+ Codec.Automotive.CSE.Internal: makeM4' :: K3 -> M1 -> Word32 -> M4
+ Codec.Automotive.CSE.Internal: makeM5 :: K4 -> M4 -> M5
+ Codec.Automotive.CSE.Internal: makeUID :: MonadPlus m => ByteString -> m UID
+ Codec.Automotive.CSE.Internal: type K1 = DerivedCipher Auth Enc
+ Codec.Automotive.CSE.Internal: type K1' = Derived Auth Enc
+ Codec.Automotive.CSE.Internal: type K2 = DerivedCipher Auth Mac
+ Codec.Automotive.CSE.Internal: type K2' = Derived Auth Mac
+ Codec.Automotive.CSE.Internal: type K3 = DerivedCipher NotAuth Enc
+ Codec.Automotive.CSE.Internal: type K3' = Derived NotAuth Enc
+ Codec.Automotive.CSE.Internal: type K4 = DerivedCipher NotAuth Mac
+ Codec.Automotive.CSE.Internal: type K4' = Derived NotAuth Mac
+ Codec.Automotive.CSE.Internal: unDerived :: Derived k c -> ByteString
+ Codec.Automotive.CSE.Internal: unKeyAuthUse :: KeyAuthUse k -> ByteString
+ Codec.Automotive.CSE.Internal: unM1 :: M1 -> ByteString
+ Codec.Automotive.CSE.Internal: unM2 :: M2 -> ByteString
+ Codec.Automotive.CSE.Internal: unM3 :: M3 -> ByteString
+ Codec.Automotive.CSE.Internal: unM4 :: M4 -> ByteString
+ Codec.Automotive.CSE.Internal: unM5 :: M5 -> ByteString
+ Codec.Automotive.CSE.Internal: unUID :: UID -> ByteString
+ Codec.Automotive.CSE.Internal: unsafeMakeDerived :: MonadPlus m => ByteString -> m (Derived k c)
+ Codec.Automotive.CSE.Internal: unsafeMakeDerivedCipher :: MonadPlus m => ByteString -> m (DerivedCipher k c)
Files
- automotive-cse.cabal +4/−2
- src/Codec/Automotive/CSE.hs +2/−281
- src/Codec/Automotive/CSE/Internal.hs +296/−0
automotive-cse.cabal view
@@ -1,6 +1,6 @@ name: automotive-cse-version: 0.1.2.0+version: 0.1.3.0 synopsis: Automotive CSE emulation description: This package includes Cryptography Security Engine (CSE) codec emulation for automotive things.@@ -20,7 +20,9 @@ cabal-version: >=1.10 library- exposed-modules: Codec.Automotive.CSE+ exposed-modules:+ Codec.Automotive.CSE+ Codec.Automotive.CSE.Internal other-modules: Backport.Crypto.MAC.CMAC
src/Codec/Automotive/CSE.hs view
@@ -1,285 +1,6 @@ --- CSE (Cryptographic Service Engine) emulation implementation module Codec.Automotive.CSE (- M1, unM1, makeM1, extractM1,- M2, unM2, makeM2,- M3, unM3, makeM3,- M4, unM4, makeM4, extractM4, makeM4', extractM4',- M5, unM5, makeM5,-- K1, K1', makeK1,- K2, K2', makeK2,- K3, K3', makeK3,- K4, K4', makeK4,-- UID, unUID, makeUID,-- Derived, unDerived,- kdf, keyUpdateEncC, keyUpdateMacC,-- DerivedCipher, derivedCipher,-- KeyAuthUse, Auth, NotAuth,- makeKeyAuthUse, unKeyAuthUse,-- UpdateC, Enc, Mac,+ module Codec.Automotive.CSE.Internal ) where -import Control.Monad (MonadPlus, guard)-import Data.Monoid ((<>), mconcat, Endo (..))-import Data.Bits (shiftL, shiftR, (.&.), (.|.))-import Data.Word (Word8, Word32)-import Data.ByteString (ByteString)-import qualified Data.ByteString as BS-import Data.ByteString.Short (ShortByteString)-import qualified Data.ByteString.Short as Short-import Data.Serialize.Get (runGet, getWord64be)-import Data.Serialize.Put (runPut, putWord64be)-import Numeric (showHex)--import qualified Data.ByteArray as B-import Crypto.Cipher.Types (cipherInit, ecbEncrypt, cbcEncrypt, nullIV, ecbDecrypt)-import Crypto.Cipher.AES (AES128)-import Crypto.Error (eitherCryptoError)--import Backport.Crypto.MAC.CMAC (CMAC(..), cmac)-import Backport.Crypto.ConstructHash.MiyaguchiPreneel (MiyaguchiPreneel(..), mp)---dump8 :: [Word8] -> String-dump8 = (`appEndo` "") . mconcat . map (Endo . showW8)- where- showW8 w- | w < 16 = ('0' :) . showHex w- | otherwise = showHex w--hdump :: ByteString -> String-hdump = dump8 . BS.unpack--hdump' :: ShortByteString -> String-hdump' = dump8 . Short.unpack---data Enc-data Mac--newtype UpdateC c =- UpdateC ByteString- deriving Eq--instance Show (UpdateC c) where- show (UpdateC c) = unwords ["UpdateC", hdump c]--keyUpdateEncC :: UpdateC Enc-keyUpdateEncC =- UpdateC . runPut $- putWord64be 0x0101534845008000 >>- putWord64be 0x00000000000000B0- --- 0x010153484500800000000000000000B0--keyUpdateMacC :: UpdateC Mac-keyUpdateMacC =- UpdateC . runPut $- putWord64be 0x0102534845008000 >>- putWord64be 0x00000000000000B0- -- 0x010253484500800000000000000000B0--data Auth-data NotAuth--newtype KeyAuthUse k =- KeyAuthUse ShortByteString- deriving Eq--makeKeyAuthUse :: MonadPlus m => ByteString -> m (KeyAuthUse k)-makeKeyAuthUse k = do- guard $ BS.length k == 16- return . KeyAuthUse $ Short.toShort k--unKeyAuthUse :: KeyAuthUse k -> ByteString-unKeyAuthUse (KeyAuthUse bs) = Short.fromShort bs--newtype Derived k c =- Derived ShortByteString- deriving Eq--instance Show (Derived k c) where- show (Derived k) = unwords ["DerivedCipher", hdump' k]--unDerived :: Derived k c -> ByteString-unDerived (Derived k) = Short.fromShort k--kdf :: KeyAuthUse k -> UpdateC c -> Derived k c-kdf k (UpdateC c) =- Derived . Short.toShort . B.convert- $ chashGetBytes (mp $ unKeyAuthUse k <> c :: MiyaguchiPreneel AES128)--kdfEnc :: KeyAuthUse k -> Derived k Enc-kdfEnc = (`kdf` keyUpdateEncC)--kdfMac :: KeyAuthUse k -> Derived k Mac-kdfMac = (`kdf` keyUpdateMacC)--newtype DerivedCipher k c = DerivedCipher AES128--derivedCipher :: Derived k c -> DerivedCipher k c-derivedCipher k =- DerivedCipher- . either (error . ("Codec.Automotive.CSE.derivedCipher: internal error: " ++) . show) id- -- assume refined length (16 byte) of miyaguchi-preneel AES128 result- . eitherCryptoError . cipherInit $ unDerived k--type K1' = Derived Auth Enc-type K1 = DerivedCipher Auth Enc--makeK1 :: KeyAuthUse Auth -- ^ AuthKey Data- -> K1' -- ^ Result Hash value-makeK1 = kdfEnc--type K2' = Derived Auth Mac-type K2 = DerivedCipher Auth Mac--makeK2 :: KeyAuthUse Auth -- ^ AuthKey Data- -> K2' -- ^ Result Hash value-makeK2 = kdfMac--type K3' = Derived NotAuth Enc-type K3 = DerivedCipher NotAuth Enc--makeK3 :: KeyAuthUse NotAuth -- ^ Key Data- -> K3' -- ^ Result Hash value-makeK3 = kdfEnc--type K4' = Derived NotAuth Mac-type K4 = DerivedCipher NotAuth Mac--makeK4 :: KeyAuthUse NotAuth -- ^ Key Data- -> K4' -- ^ Result Hash value-makeK4 = kdfMac---newtype UID = UID ShortByteString deriving (Eq, Ord)--instance Show UID where- show (UID s) = unwords ["UID", hdump' s]--unUID :: UID -> ByteString-unUID (UID u) = Short.fromShort u--makeUID :: MonadPlus m => ByteString -> m UID-makeUID s = do- guard $ BS.length s == 15- return . UID $ Short.toShort s--newtype M1 = M1 ByteString deriving Eq--instance Show M1 where- show (M1 s) = unwords ["M1", hdump s]--makeM1 :: UID -- ^ UID - 15 octet- -> Word8 -- ^ Key ID - 4 bit- -> Word8 -- ^ Auth key ID - 4 bit- -> M1-makeM1 uid kid akid = M1 $ unUID uid <> BS.singleton (kid `shiftL` 4 .|. akid)--unM1 :: M1 -> ByteString-unM1 (M1 m1) = m1--extractM1 :: M1 -> (UID, Word8, Word8)-extractM1 (M1 m1) = (UID $ Short.toShort uid, lw `shiftR` 4, lw .&. 0x0F)- where- (uid, x) = BS.splitAt 15 m1- lw = head $ BS.unpack x- -- assume refined M1--newtype M2 = M2 ByteString deriving Eq--instance Show M2 where- show (M2 s) = unwords ["M2", hdump s]--makeM2 :: K1 -- ^ K1 value- -> Word32 -- ^ Counter - 28 bit- -> Word8 -- ^ Key Flag - 6 bit- -> KeyAuthUse NotAuth -- ^ Key Data for AES128- -> M2-makeM2 (DerivedCipher k1) counter flags keyData =- M2 $ cbcEncrypt k1 nullIV plain- where- plain = (runPut $ do- putWord64be $- fromIntegral counter `shiftL` 36 .|.- fromIntegral flags `shiftL` 30- --- fromIntegral (flags `shiftR` 1) `shiftL` 31 --- SHE standard- putWord64be 0)- <> unKeyAuthUse keyData--unM2 :: M2 -> ByteString-unM2 (M2 m2) = m2--newtype M3 = M3 ByteString deriving Eq--instance Show M3 where- show (M3 s) = unwords ["M3", hdump s]--makeM3 :: K2- -> M1- -> M2- -> M3-makeM3 (DerivedCipher k2) (M1 m1) (M2 m2) = M3 . B.convert . cmacGetBytes . cmac k2 $ m1 <> m2--unM3 :: M3 -> ByteString-unM3 (M3 m3) = m3--newtype M4 = M4 ByteString deriving Eq--instance Show M4 where- show (M4 s) = unwords ["M4", hdump s]--makeM4' :: K3- -> M1- -> Word32- -> M4-makeM4' (DerivedCipher k3) (M1 m1) counter =- M4 $ m1 <> ecbEncrypt k3 p2- where- p2 = runPut $ do- putWord64be $- fromIntegral counter `shiftL` 36 .|.- 1 `shiftL` 35- putWord64be 0--makeM4 :: K3- -> UID- -> Word8- -> Word8- -> Word32- -> M4-makeM4 k3 uid kid akid counter =- makeM4' k3 (makeM1 uid kid akid) counter--unM4 :: M4 -> ByteString-unM4 (M4 m4) = m4--extractM4' :: K3 -> M4 -> (M1, Word32)-extractM4' (DerivedCipher k3) (M4 m4) = (M1 m1, fromIntegral $ w64 `shiftR` 36)- where- (m1, m4') = BS.splitAt 16 m4- w64 = either (error . ("Codec.Automotive.CSE.extractM4: internal error: " ++)) id- . runGet getWord64be $ ecbDecrypt k3 m4'--extractM4 :: K3 -> M4 -> ((UID, Word8, Word8), Word32)-extractM4 k3 m4 = (extractM1 m1, counter)- where (m1, counter) = extractM4' k3 m4--newtype M5 = M5 ByteString deriving Eq--instance Show M5 where- show (M5 s) = unwords ["M5", hdump s]--makeM5 :: K4- -> M4- -> M5-makeM5 (DerivedCipher k4) (M4 m4) = M5 . B.convert . cmacGetBytes $ cmac k4 m4--unM5 :: M5 -> ByteString-unM5 (M5 m4) = m4+import Codec.Automotive.CSE.Internal hiding (unsafeMakeDerived, unsafeMakeDerivedCipher)
+ src/Codec/Automotive/CSE/Internal.hs view
@@ -0,0 +1,296 @@++-- CSE (Cryptographic Service Engine) emulation implementation+module Codec.Automotive.CSE.Internal (+ M1, unM1, makeM1, extractM1,+ M2, unM2, makeM2,+ M3, unM3, makeM3,+ M4, unM4, makeM4, extractM4, makeM4', extractM4',+ M5, unM5, makeM5,++ K1, K1', makeK1,+ K2, K2', makeK2,+ K3, K3', makeK3,+ K4, K4', makeK4,++ UID, unUID, makeUID,++ Derived, unDerived,+ kdf, keyUpdateEncC, keyUpdateMacC,++ DerivedCipher, derivedCipher,++ KeyAuthUse, Auth, NotAuth,+ makeKeyAuthUse, unKeyAuthUse,++ UpdateC, Enc, Mac,++ unsafeMakeDerived, unsafeMakeDerivedCipher,+ ) where++import Control.Monad (MonadPlus, guard, liftM)+import Data.Monoid ((<>), mconcat, Endo (..))+import Data.Bits (shiftL, shiftR, (.&.), (.|.))+import Data.Word (Word8, Word32)+import Data.ByteString (ByteString)+import qualified Data.ByteString as BS+import Data.ByteString.Short (ShortByteString)+import qualified Data.ByteString.Short as Short+import Data.Serialize.Get (runGet, getWord64be)+import Data.Serialize.Put (runPut, putWord64be)+import Numeric (showHex)++import qualified Data.ByteArray as B+import Crypto.Cipher.Types (cipherInit, ecbEncrypt, cbcEncrypt, nullIV, ecbDecrypt)+import Crypto.Cipher.AES (AES128)+import Crypto.Error (eitherCryptoError)++import Backport.Crypto.MAC.CMAC (CMAC(..), cmac)+import Backport.Crypto.ConstructHash.MiyaguchiPreneel (MiyaguchiPreneel(..), mp)+++dump8 :: [Word8] -> String+dump8 = (`appEndo` "") . mconcat . map (Endo . showW8)+ where+ showW8 w+ | w < 16 = ('0' :) . showHex w+ | otherwise = showHex w++hdump :: ByteString -> String+hdump = dump8 . BS.unpack++hdump' :: ShortByteString -> String+hdump' = dump8 . Short.unpack+++data Enc+data Mac++newtype UpdateC c =+ UpdateC ByteString+ deriving Eq++instance Show (UpdateC c) where+ show (UpdateC c) = unwords ["UpdateC", hdump c]++keyUpdateEncC :: UpdateC Enc+keyUpdateEncC =+ UpdateC . runPut $+ putWord64be 0x0101534845008000 >>+ putWord64be 0x00000000000000B0+ --- 0x010153484500800000000000000000B0++keyUpdateMacC :: UpdateC Mac+keyUpdateMacC =+ UpdateC . runPut $+ putWord64be 0x0102534845008000 >>+ putWord64be 0x00000000000000B0+ -- 0x010253484500800000000000000000B0++data Auth+data NotAuth++newtype KeyAuthUse k =+ KeyAuthUse ShortByteString+ deriving Eq++makeKeyAuthUse :: MonadPlus m => ByteString -> m (KeyAuthUse k)+makeKeyAuthUse k = do+ guard $ BS.length k == 16+ return . KeyAuthUse $ Short.toShort k++unKeyAuthUse :: KeyAuthUse k -> ByteString+unKeyAuthUse (KeyAuthUse bs) = Short.fromShort bs++newtype Derived k c =+ Derived ShortByteString+ deriving Eq++instance Show (Derived k c) where+ show (Derived k) = unwords ["DerivedCipher", hdump' k]++-- | Specifying derived key directly.+unsafeMakeDerived :: MonadPlus m => ByteString -> m (Derived k c)+unsafeMakeDerived k = do+ guard $ BS.length k == 16+ return . Derived $ Short.toShort k++unDerived :: Derived k c -> ByteString+unDerived (Derived k) = Short.fromShort k++kdf :: KeyAuthUse k -> UpdateC c -> Derived k c+kdf k (UpdateC c) =+ Derived . Short.toShort . B.convert+ $ chashGetBytes (mp $ unKeyAuthUse k <> c :: MiyaguchiPreneel AES128)++kdfEnc :: KeyAuthUse k -> Derived k Enc+kdfEnc = (`kdf` keyUpdateEncC)++kdfMac :: KeyAuthUse k -> Derived k Mac+kdfMac = (`kdf` keyUpdateMacC)++newtype DerivedCipher k c = DerivedCipher AES128++derivedCipher :: Derived k c -> DerivedCipher k c+derivedCipher k =+ DerivedCipher+ . either (error . ("Codec.Automotive.CSE.derivedCipher: internal error: " ++) . show) id+ -- assume refined length (16 byte) of miyaguchi-preneel AES128 result+ . eitherCryptoError . cipherInit $ unDerived k++unsafeMakeDerivedCipher :: MonadPlus m => ByteString -> m (DerivedCipher k c)+unsafeMakeDerivedCipher = liftM derivedCipher . unsafeMakeDerived++type K1' = Derived Auth Enc+type K1 = DerivedCipher Auth Enc++makeK1 :: KeyAuthUse Auth -- ^ AuthKey Data+ -> K1' -- ^ Result Hash value+makeK1 = kdfEnc++type K2' = Derived Auth Mac+type K2 = DerivedCipher Auth Mac++makeK2 :: KeyAuthUse Auth -- ^ AuthKey Data+ -> K2' -- ^ Result Hash value+makeK2 = kdfMac++type K3' = Derived NotAuth Enc+type K3 = DerivedCipher NotAuth Enc++makeK3 :: KeyAuthUse NotAuth -- ^ Key Data+ -> K3' -- ^ Result Hash value+makeK3 = kdfEnc++type K4' = Derived NotAuth Mac+type K4 = DerivedCipher NotAuth Mac++makeK4 :: KeyAuthUse NotAuth -- ^ Key Data+ -> K4' -- ^ Result Hash value+makeK4 = kdfMac+++newtype UID = UID ShortByteString deriving (Eq, Ord)++instance Show UID where+ show (UID s) = unwords ["UID", hdump' s]++unUID :: UID -> ByteString+unUID (UID u) = Short.fromShort u++makeUID :: MonadPlus m => ByteString -> m UID+makeUID s = do+ guard $ BS.length s == 15+ return . UID $ Short.toShort s++newtype M1 = M1 ByteString deriving Eq++instance Show M1 where+ show (M1 s) = unwords ["M1", hdump s]++makeM1 :: UID -- ^ UID - 15 octet+ -> Word8 -- ^ Key ID - 4 bit+ -> Word8 -- ^ Auth key ID - 4 bit+ -> M1+makeM1 uid kid akid = M1 $ unUID uid <> BS.singleton (kid `shiftL` 4 .|. akid)++unM1 :: M1 -> ByteString+unM1 (M1 m1) = m1++extractM1 :: M1 -> (UID, Word8, Word8)+extractM1 (M1 m1) = (UID $ Short.toShort uid, lw `shiftR` 4, lw .&. 0x0F)+ where+ (uid, x) = BS.splitAt 15 m1+ lw = head $ BS.unpack x+ -- assume refined M1++newtype M2 = M2 ByteString deriving Eq++instance Show M2 where+ show (M2 s) = unwords ["M2", hdump s]++makeM2 :: K1 -- ^ K1 value+ -> Word32 -- ^ Counter - 28 bit+ -> Word8 -- ^ Key Flag - 6 bit+ -> KeyAuthUse NotAuth -- ^ Key Data for AES128+ -> M2+makeM2 (DerivedCipher k1) counter flags keyData =+ M2 $ cbcEncrypt k1 nullIV plain+ where+ plain = (runPut $ do+ putWord64be $+ fromIntegral counter `shiftL` 36 .|.+ fromIntegral flags `shiftL` 30+ --- fromIntegral (flags `shiftR` 1) `shiftL` 31 --- SHE standard+ putWord64be 0)+ <> unKeyAuthUse keyData++unM2 :: M2 -> ByteString+unM2 (M2 m2) = m2++newtype M3 = M3 ByteString deriving Eq++instance Show M3 where+ show (M3 s) = unwords ["M3", hdump s]++makeM3 :: K2+ -> M1+ -> M2+ -> M3+makeM3 (DerivedCipher k2) (M1 m1) (M2 m2) = M3 . B.convert . cmacGetBytes . cmac k2 $ m1 <> m2++unM3 :: M3 -> ByteString+unM3 (M3 m3) = m3++newtype M4 = M4 ByteString deriving Eq++instance Show M4 where+ show (M4 s) = unwords ["M4", hdump s]++makeM4' :: K3+ -> M1+ -> Word32+ -> M4+makeM4' (DerivedCipher k3) (M1 m1) counter =+ M4 $ m1 <> ecbEncrypt k3 p2+ where+ p2 = runPut $ do+ putWord64be $+ fromIntegral counter `shiftL` 36 .|.+ 1 `shiftL` 35+ putWord64be 0++makeM4 :: K3+ -> UID+ -> Word8+ -> Word8+ -> Word32+ -> M4+makeM4 k3 uid kid akid counter =+ makeM4' k3 (makeM1 uid kid akid) counter++unM4 :: M4 -> ByteString+unM4 (M4 m4) = m4++extractM4' :: K3 -> M4 -> (M1, Word32)+extractM4' (DerivedCipher k3) (M4 m4) = (M1 m1, fromIntegral $ w64 `shiftR` 36)+ where+ (m1, m4') = BS.splitAt 16 m4+ w64 = either (error . ("Codec.Automotive.CSE.extractM4: internal error: " ++)) id+ . runGet getWord64be $ ecbDecrypt k3 m4'++extractM4 :: K3 -> M4 -> ((UID, Word8, Word8), Word32)+extractM4 k3 m4 = (extractM1 m1, counter)+ where (m1, counter) = extractM4' k3 m4++newtype M5 = M5 ByteString deriving Eq++instance Show M5 where+ show (M5 s) = unwords ["M5", hdump s]++makeM5 :: K4+ -> M4+ -> M5+makeM5 (DerivedCipher k4) (M4 m4) = M5 . B.convert . cmacGetBytes $ cmac k4 m4++unM5 :: M5 -> ByteString+unM5 (M5 m4) = m4