diff --git a/ChangeLog.md b/ChangeLog.md index 74a8a6e..8ee3e4c 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,5 +1,5 @@ # Revision history for fernet -## 0.1.0.0 -- YYYY-mm-dd +## 0.1.0.0 -- 2017-03-22 * First version. Released on an unsuspecting world. diff --git a/fernet.cabal b/fernet.cabal index 879d546..63ad71a 100644 --- a/fernet.cabal +++ b/fernet.cabal @@ -1,7 +1,11 @@ name: fernet version: 0.1.0.0 -synopsis: Generates and verifies HMAC-based authentication tokens. --- description: +synopsis: Generate and verify HMAC-based authentication tokens. +description: Originally designed for use within OpenStack clusters, + /Fernet/ is intended to be fast and light-weight, with + non-persistent tokens. Fernet tokens are signed with a + SHA256 HMAC and their contents encrypted with AES128 + in CBC mode. homepage: https://github.com/rvl/fernet-hs license: LGPL-3 license-file: LICENSE diff --git a/src/Network/Fernet.hs b/src/Network/Fernet.hs index d43d385..0957df2 100644 --- a/src/Network/Fernet.hs +++ b/src/Network/Fernet.hs @@ -61,8 +61,7 @@ import Data.Byteable (constEqBytes) import Data.Word (Word8) import Data.Time.Clock (NominalDiffTime) import Data.Time.Clock.POSIX (POSIXTime, getPOSIXTime) - -import Data.Bifunctor (first) +import Data.Bifunctor (first) import Network.Fernet.Crypto import Network.Fernet.Key @@ -155,12 +154,12 @@ decrypt' Key{..} ttl now t = do checkExpiry ttl now fields checkSignature signingKey tb sig checkInputSize fields - case aesDecrypt encryptionKey (tfIV fields) (tfCiphertext fields) of + case aesDecrypt encryptionKey (tokenIV fields) (tokenCiphertext fields) of Just text -> Right text Nothing -> Left KeySizeInvalid checkVersion :: TokenFields -> Either DecryptError () -checkVersion tf | tfVersion tf == version = Right () +checkVersion tf | tokenVersion tf == version = Right () | otherwise = Left UnsupportedVersion -- | Maximum clock skew in the future direction. @@ -168,7 +167,7 @@ maxClockSkew :: NominalDiffTime maxClockSkew = 60 checkTimestamp :: POSIXTime -> TokenFields -> Either DecryptError () -checkTimestamp now TokenFields{..} | tfTimestamp - now <= maxClockSkew = Right () +checkTimestamp now TokenFields{..} | tokenTimestamp - now <= maxClockSkew = Right () | otherwise = Left UnacceptableClockSkew checkExpiry :: NominalDiffTime -> POSIXTime -> TokenFields -> Either DecryptError () @@ -180,6 +179,6 @@ checkSignature k tf sig | constEqBytes sig (sign k tf) = Right () | otherwise = Left TokenInvalid checkInputSize :: TokenFields -> Either DecryptError () -checkInputSize tf | isBlocked (tfCiphertext tf) = Right () - | otherwise = Left InvalidBlockSize +checkInputSize tf | isBlocked (tokenCiphertext tf) = Right () + | otherwise = Left InvalidBlockSize where isBlocked t = BS.length t `mod` cipherBlockSize == 0 diff --git a/src/Network/Fernet/Token.hs b/src/Network/Fernet/Token.hs index 52f6138..ac3bba6 100644 --- a/src/Network/Fernet/Token.hs +++ b/src/Network/Fernet/Token.hs @@ -10,10 +10,9 @@ module Network.Fernet.Token , Signature ) where -import Data.ByteString (ByteString) +import Data.ByteString (ByteString) import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as BL - import Data.Word (Word8) import Data.Time.Clock.POSIX (POSIXTime, getPOSIXTime) import Data.Time.Clock (NominalDiffTime) @@ -23,10 +22,10 @@ import Data.Binary.Put import Network.Fernet.Base64 data TokenFields = TokenFields - { tfVersion :: Word8 -- ^ Version, 8 bits - , tfTimestamp :: POSIXTime -- ^ Timestamp, 64 bits - , tfIV :: ByteString -- ^ IV, 128 bits - , tfCiphertext :: ByteString -- ^ Ciphertext, variable length, multiple of 128 bits + { tokenVersion :: Word8 -- ^ Version, 8 bits + , tokenTimestamp :: POSIXTime -- ^ Timestamp, 64 bits + , tokenIV :: ByteString -- ^ IV, 128 bits + , tokenCiphertext :: ByteString -- ^ Ciphertext, variable length, multiple of 128 bits } deriving (Show, Eq) type Signature = ByteString @@ -51,10 +50,10 @@ decode = (>>= decode') . b64urldec serialize :: TokenFields -> ByteString serialize TokenFields{..} = BL.toStrict . runPut $ do - putWord8 tfVersion - putWord64be (floor tfTimestamp) - putByteString tfIV - putByteString tfCiphertext + putWord8 tokenVersion + putWord64be (floor tokenTimestamp) + putByteString tokenIV + putByteString tokenCiphertext deserialize :: ByteString -> Either String TokenFields deserialize t = case runGetOrFail get (BL.fromStrict t) of @@ -85,4 +84,4 @@ isExpired ttl token now = do return $ hasExpired' ttl now tf hasExpired' :: NominalDiffTime -> POSIXTime -> TokenFields -> Bool -hasExpired' ttl now TokenFields{..} = now - tfTimestamp < ttl +hasExpired' ttl now TokenFields{..} = now - tokenTimestamp < ttl