packages feed

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 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