commsec 0.3.3 → 0.3.4
raw patch · 4 files changed
+41/−37 lines, 4 filesdep ~cipher-aes128
Dependency ranges changed: cipher-aes128
Files
- Network/CommSec.hs +3/−12
- Network/CommSec/Package.hs +31/−19
- Network/CommSec/Types.hs +5/−4
- commsec.cabal +2/−2
Network/CommSec.hs view
@@ -20,7 +20,7 @@ import Crypto.Classes (buildKey) import Crypto.Cipher.AES128.Internal (encryptCTR)-import Crypto.Cipher.AES128 (AESKey)+import Crypto.Cipher.AES128 (AESKey128, ctr, zeroIV) import Network.CommSec.Package import Network.CommSec.Types import Network.Socket ( Socket, SocketType(..), SockAddr, AddrInfo(..)@@ -161,19 +161,10 @@ -- Use counter mode to expand input entropy that is at least 16 bytes long expandSecret :: B.ByteString -> Int -> B.ByteString expandSecret entropy sz =- let k = buildKey entropy+ let k = buildKey entropy :: Maybe AESKey128 in case k of Nothing -> error "Build key failed"- Just key ->- let iv = B.replicate 16 0- in enc key iv input- where- input = B.replicate sz 0- enc :: AESKey -> B.ByteString -> B.ByteString -> B.ByteString- enc k i pt = B.unsafeCreate sz $ \ctPtr ->- B.useAsCString pt $ \ptPtr ->- B.useAsCString i $ \iv ->- encryptCTR k (castPtr iv) nullPtr (castPtr ctPtr) (castPtr ptPtr) sz+ Just key -> fst $ ctr key zeroIV (B.replicate sz 0) -- |Expands the provided 128 (or more) bit secret into two -- keys to create a connection.
Network/CommSec/Package.hs view
@@ -37,7 +37,7 @@ import Prelude hiding (seq) import qualified Crypto.Cipher.AES128.Internal as AES-import Crypto.Cipher.AES128.Internal (GCM)+import Crypto.Cipher.AES128.Internal (GCMpc, AESKey128) import Crypto.Cipher.AES128 () import qualified Data.ByteString.Internal as B import qualified Data.ByteString as B@@ -68,28 +68,34 @@ -- -- [CNT (used for both the IV and seq) | CT of Payload | ICV] +-- | A tuple of key and precomputed data for use by GCM+data GCMdata = GCMdata { gcmkey :: AESKey128+ , gcmpc :: GCMpc+ }++ -- | A context useful for sending data. data OutContext = Out { aesCtr :: {-# UNPACK #-} !Word64 , saltOut :: {-# UNPACK #-} !Word32- , outKey :: GCM+ , outKey :: GCMdata } -- | A context useful for receiving data. data InContext- = In { bitWindow :: {-# UNPACK #-} !BitWindow+ = In { bitWindow :: {-# UNPACK #-} !BitWindow , saltIn :: {-# UNPACK #-} !Word32- , inKey :: GCM+ , inKey :: GCMdata } | InStrict { seqVal :: {-# UNPACK #-} !Word64 , saltIn :: {-# UNPACK #-} !Word32- , inKey :: GCM+ , inKey :: GCMdata } | InSequential { seqVal :: {-# UNPACK #-} !Word64 , saltIn :: {-# UNPACK #-} !Word32- , inKey :: GCM+ , inKey :: GCMdata } @@ -119,13 +125,19 @@ StrictOrdering -> InStrict {..} Sequential -> InSequential {..} -buildGCM :: B.ByteString -> GCM-buildGCM key = unsafePerformIO $ do- B.unsafeUseAsCString key $ \bPtr -> AES.generateGCM (castPtr bPtr)+buildGCM :: B.ByteString -> GCMdata+buildGCM key + | B.length key >= 16 = unsafePerformIO $+ B.unsafeUseAsCString key $ \bPtr -> do+ kStruct <- AES.generateKey128 (castPtr bPtr)+ case kStruct of+ Just t -> GCMdata t `fmap` AES.precomputeGCMdata t+ Nothing -> throw BuildKeyFailure+ | otherwise = throw BuildKeyFailure -- Encrypts multiple-of-block-sized input, returing a bytestring of the -- [ctr, ct, tag].-encryptGCM :: GCM+encryptGCM :: GCMdata -> Word64 -- ^ AES GCM Counter (IV) -> Word32 -- ^ Salt -> ByteString -- ^ Plaintext@@ -138,14 +150,14 @@ -- Encrypts multiple-of-block-sized input, filling a pointer with the -- result of [ctr, ct, tag].-encryptGCMPtr :: GCM+encryptGCMPtr :: GCMdata -> Word64 -- ^ AES GCM Counter (IV) -> Word32 -- ^ Salt -> Ptr Word8 -- ^ Plaintext buffer -> Int -- ^ Plaintext length -> Ptr Word8 -- ^ ciphertext buffer (at least encBytes large) -> IO ()-encryptGCMPtr key ctr salt ptPtr ptLen ctPtr = do+encryptGCMPtr (GCMdata {..}) ctr salt ptPtr ptLen ctPtr = do let ivLen = sizeOf ctr + sizeOf salt tagLen = gTagLen allocaBytes ivLen $ \ptrIV -> do@@ -155,10 +167,10 @@ pokeBE ctPtr ctr let tagPtr = ctPtr' `plusPtr` ptLen ctPtr' = ctPtr `plusPtr` sizeOf ctr- AES.encryptGCM key ptrIV ivLen (castPtr ptPtr) ptLen nullPtr 0 (castPtr ctPtr') tagPtr+ AES.encryptGCM gcmkey gcmpc ptrIV (fromIntegral ivLen) nullPtr 0 (castPtr ptPtr) (fromIntegral ptLen) (castPtr ctPtr') tagPtr -- | GCM decrypt and verify ICV.-decryptGCMPtr :: GCM+decryptGCMPtr :: GCMdata -> Word64 -- ^ AES GCM Counter (IV) -> Word32 -- ^ Salt -> Ptr Word8 -- ^ Ciphertext@@ -167,7 +179,7 @@ -> Int -- ^ Tag length -> Ptr Word8 -- ^ Plaintext result ptr (at least 'decBytes' large) -> IO (Either CommSecError ())-decryptGCMPtr key ctr salt ctPtr ctLen tagPtr tagLen ptPtr+decryptGCMPtr (GCMdata {..}) ctr salt ctPtr ctLen tagPtr tagLen ptPtr | tagLen /= gTagLen = return $ Left InvalidICV | otherwise = do let ivLen = sizeOf ctr + sizeOf salt@@ -176,7 +188,7 @@ -- Build the IV pokeBE32 ptrIV salt pokeBE (ptrIV `plusPtr` sizeOf salt) ctr- AES.decryptGCM key ptrIV ivLen (castPtr ctPtr) paddedLen nullPtr 0 (castPtr ptPtr) ctagPtr+ AES.decryptGCM gcmkey gcmpc ptrIV (fromIntegral ivLen) nullPtr 0 (castPtr ctPtr) (fromIntegral paddedLen) (castPtr ptPtr) ctagPtr w1 <- peekBE ctagPtr w2 <- peekBE (ctagPtr `plusPtr` sizeOf w1) y1 <- peekBE (castPtr tagPtr)@@ -187,13 +199,13 @@ -- Decrypts multiple-of-block-sized input, returing a bytestring of the -- [ctr, ct, tag].-decryptGCM :: GCM+decryptGCM :: GCMdata -> Word64 -- ^ AES GCM Counter (IV) -> Word32 -- ^ Salt -> ByteString -- ^ Ciphertext -> ByteString -- ^ Tag -> Either CommSecError ByteString -- Plaintext (or an exception due to bad tag)-decryptGCM key ctr salt ct tag+decryptGCM (GCMdata {..}) ctr salt ct tag | B.length tag < gTagLen = Left InvalidICV | otherwise = unsafePerformIO $ do let ivLen = sizeOf ctr + sizeOf salt@@ -206,7 +218,7 @@ B.unsafeUseAsCString tag $ \tagPtr -> do B.unsafeUseAsCString ct $ \ptrCT -> do pt <- B.create paddedLen $ \ptrPT -> do- AES.decryptGCM key ptrIV ivLen (castPtr ptrCT) (B.length ct) nullPtr 0 (castPtr ptrPT) ctagPtr+ AES.decryptGCM gcmkey gcmpc ptrIV (fromIntegral ivLen) nullPtr 0 (castPtr ptrCT) (fromIntegral $ B.length ct) (castPtr ptrPT) ctagPtr w1 <- peekBE ctagPtr w2 <- peekBE (ctagPtr `plusPtr` sizeOf w1) y1 <- peekBE (castPtr tagPtr)
Network/CommSec/Types.hs view
@@ -9,10 +9,11 @@ -- |Errors that can be returned by the decoding/receicing operations. data CommSecError- = OldContext -- The context is too old (sequence number rollover)- | DuplicateSeq -- The sequence number we previously seen (possible replay attack)- | InvalidICV -- The integrity check value is invalid- | BadPadding -- The padding was invalid (corrupt sender?)+ = OldContext -- The context is too old (sequence number rollover)+ | DuplicateSeq -- The sequence number we previously seen (possible replay attack)+ | InvalidICV -- The integrity check value is invalid+ | BadPadding -- The padding was invalid (corrupt sender?)+ | BuildKeyFailure -- The entropy was insufficent to build a key (bytestring too short) deriving (Eq,Ord,Show,Enum,Data,Typeable) -- |Policy for misordered packets. Notice StrictOrdering does not mean
commsec.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/ name: commsec-version: 0.3.3+version: 0.3.4 synopsis: Provide communications security using symmetric ephemeral keys description: This package provides confidentiallity, integrity and replay detection. Users must@@ -24,7 +24,7 @@ exposed-modules: Network.CommSec, Network.CommSec.Package, Network.CommSec.BitWindow, Network.CommSec.Types -- other-modules: Network.CommSec.BitWindow, Network.CommSec.Types build-depends: base >4.5 && < 5,- cipher-aes128 >= 0.5,+ cipher-aes128 >= 0.6.1, bytestring, crypto-api >= 0.12, network >= 2.4.1