packages feed

one-time-password 1.0.0.1 → 2.0.0

raw patch · 3 files changed

+72/−71 lines, 3 filesdep +cryptonitedep +memorydep −byteabledep −cryptohashPVP ok

version bump matches the API change (PVP)

Dependencies added: cryptonite, memory

Dependencies removed: byteable, cryptohash

API changes (from Hackage documentation)

- Data.OTP: hotp :: HashAlgorithm a => a -> ByteString -> Word64 -> Word -> Word32
+ Data.OTP: hotp :: forall a key. (HashAlgorithm a, ByteArrayAccess key) => a -> key -> Word64 -> Word -> Word32
- Data.OTP: hotpCheck :: HashAlgorithm a => a -> ByteString -> (Word64, Word64) -> Word64 -> Word -> Word32 -> Bool
+ Data.OTP: hotpCheck :: (HashAlgorithm a, ByteArrayAccess key) => a -> key -> (Word64, Word64) -> Word64 -> Word -> Word32 -> Bool
- Data.OTP: totp :: HashAlgorithm a => a -> ByteString -> UTCTime -> Word64 -> Word -> Word32
+ Data.OTP: totp :: (HashAlgorithm a, ByteArrayAccess key) => a -> key -> UTCTime -> Word64 -> Word -> Word32
- Data.OTP: totpCheck :: HashAlgorithm a => a -> ByteString -> (Word64, Word64) -> UTCTime -> Word64 -> Word -> Word32 -> Bool
+ Data.OTP: totpCheck :: (HashAlgorithm a, ByteArrayAccess key) => a -> key -> (Word64, Word64) -> UTCTime -> Word64 -> Word -> Word32 -> Bool

Files

CHANGELOG.md view
@@ -1,5 +1,11 @@ # CHANGELOG +## 2.0.0+### Changed+* Change versioning to semver+* Use `cryptonite` instead of deprecated `cryptohash` (broken backwards+  compatibility)+ ## 1.0.0.1  * Documentation typos fixed
one-time-password.cabal view
@@ -1,8 +1,5 @@ name:                one-time-password--- PVP summary:      +-+------- breaking API changes---                   | | +----- non-breaking API additions---                   | | | +--- code changes with no API change-version:             1.0.0.1+version:             2.0.0 synopsis:            HMAC-Based and Time-Based One-Time Passwords  description: Implements HMAC-Based One-Time Password Algorithm as@@ -11,7 +8,7 @@  license:        MIT license-file:   LICENSE-copyright:      (c) 2012 Artem Leshchev, 2015 Aleksey Uimanov+copyright:      (c) 2012 Artem Leshchev, 2016 Aleksey Uimanov author:         Artem Leshchev, Aleksey Uimanov maintainer:     s9gf4ult@gmail.com <Aleksey Uimanov> homepage:       https://github.com/s9gf4ult/one-time-password@@ -30,37 +27,30 @@ library   default-language:  Haskell2010   hs-source-dirs:    src-   default-extensions: OverloadedStrings-+                    , ScopedTypeVariables   exposed-modules:   Data.OTP-   build-depends:     base >= 3 && < 5-                   , byteable                    , bytestring                    , cereal-                   , cryptohash+                   , cryptonite+                   , memory                    , time >= 1.1-   ghc-options: -Wall  test-suite tests   default-language: Haskell2010   type:            exitcode-stdio-1.0   hs-source-dirs:  test-+  ghc-options: -Wall   default-extensions: ExistentialQuantification                     , OverloadedStrings                     , RankNTypes-   main-is:         Test.hs-   build-depends:   base >= 3 && < 5                  , bytestring-                 , cryptohash+                 , cryptonite                  , one-time-password                  , tasty                  , tasty-hunit                  , time >= 1.1--  ghc-options: -Wall
src/Data/OTP.hs view
@@ -14,9 +14,9 @@        ) where  import Crypto.Hash+import Crypto.MAC.HMAC import Data.Bits-import Data.Byteable-import Data.ByteString       (ByteString)+import Data.ByteArray (unpack, ByteArrayAccess) import Data.Serialize.Get import Data.Serialize.Put import Data.Time@@ -25,7 +25,7 @@  import qualified Data.ByteString as BS -{- | Compute HOTP using secret key and counter value.+{- | Compute HMAC-Based One-Time Password using secret key and counter value.  >>> hotp SHA1 "1234" 100 6 317569@@ -38,28 +38,28 @@  -} -hotp :: (HashAlgorithm a)-     => a                       -- ^ Hashing algorithm from module "Crypto.Hash"-     -> ByteString              -- ^ Shared secret-     -> Word64                  -- ^ Counter value-     -> Word                    -- ^ Number of digits in a password-     -> Word32                  -- ^ HOTP-hotp alg secr cnt len =-    let h = trunc-            $ toBytes-            $ hmacAlg alg secr-            $ runPut-            $ putWord64be cnt-    in h `mod` (10^len)+hotp+  :: forall a key+   . (HashAlgorithm a, ByteArrayAccess key)+  => a                       -- ^ Hashing algorithm from module "Crypto.Hash.IO"+  -> key                     -- ^ Shared secret+  -> Word64                  -- ^ Counter value+  -> Word                    -- ^ Number of digits in a password+  -> Word32                  -- ^ HOTP+hotp _ key cnt digits =+  let msg = runPut $ putWord64be cnt+      h :: HMAC a+      h = hmac key msg+      w = trunc $ unpack h+  in w `mod` (10 ^ digits)   where-    trunc :: ByteString -> Word32+    trunc :: [Word8] -> Word32     trunc b =-        let offset = BS.last b .&. 15 -- take low 4 bits of last byte-            rb = BS.take 4-                 $ BS.drop (fromIntegral offset) b -- resulting 4 byte value-        in case runGet getWord32be rb of-            Left e -> error e-            Right res -> res .&. (0x80000000 - 1) -- reset highest bit+      let offset = last b .&. 15 -- take low 4 bits of last byte+          rb = BS.pack $ take 4 $ drop (fromIntegral offset) b -- resulting 4 byte value+      in case runGet getWord32be rb of+      Left e    -> error e+      Right res -> res .&. (0x80000000 - 1) -- reset highest bit  {- | Check presented password against a valid range. @@ -92,20 +92,21 @@  -} -hotpCheck :: (HashAlgorithm a)-          => a                  -- ^ Hashing algorithm-          -> ByteString         -- ^ Shared secret-          -> (Word64, Word64)   -- ^ Valid counter range, before and after ideal-          -> Word64             -- ^ Ideal (expected) counter value-          -> Word               -- ^ Number of digits in a password-          -> Word32             -- ^ Password entered by user-          -> Bool               -- ^ True if password is valid+hotpCheck+  :: (HashAlgorithm a, ByteArrayAccess key)+  => a                  -- ^ Hashing algorithm+  -> key                -- ^ Shared secret+  -> (Word64, Word64)   -- ^ Valid counter range, before and after ideal+  -> Word64             -- ^ Ideal (expected) counter value+  -> Word               -- ^ Number of digits in a password+  -> Word32             -- ^ Password entered by user+  -> Bool               -- ^ True if password is valid hotpCheck alg secr rng cnt len pass =     let counters = counterRange rng cnt         passwds = map (\c -> hotp alg secr c len) counters     in any (pass ==) passwds -{- | Compute a TOTP using secret key and time.+{- | Compute a Time-Based One-Time Password using secret key and time.  >>> totp SHA1 "1234" (read "2010-10-10 00:01:00 UTC") 30 6 388892@@ -121,13 +122,14 @@  -} -totp :: (HashAlgorithm a)-     => a                       -- ^ Hash algorithm to use-     -> ByteString              -- ^ Shared secret-     -> UTCTime                 -- ^ Time of TOTP-     -> Word64                  -- ^ Time period in seconds-     -> Word                    -- ^ Number of digits in a password-     -> Word32                  -- ^ TOTP+totp+  :: (HashAlgorithm a, ByteArrayAccess key)+  => a         -- ^ Hash algorithm to use+  -> key       -- ^ Shared secret+  -> UTCTime   -- ^ Time of TOTP+  -> Word64    -- ^ Time range in seconds+  -> Word      -- ^ Number of digits in a password+  -> Word32    -- ^ TOTP totp alg secr time period len =     hotp alg secr (totpCounter time period) len @@ -152,15 +154,16 @@ True -} -totpCheck :: (HashAlgorithm a)-          => a                  -- ^ Hashing algorithm-          -> ByteString         -- ^ Shared secret-          -> (Word64, Word64)   -- ^ Valid counter range, before and after ideal-          -> UTCTime            -- ^ Time of TOTP-          -> Word64             -- ^ Period duration in seconds-          -> Word               -- ^ Numer of digits in a password-          -> Word32             -- ^ Password given by user-          -> Bool               -- ^ True if password is valid+totpCheck+  :: (HashAlgorithm a, ByteArrayAccess key)+  => a                  -- ^ Hashing algorithm+  -> key                -- ^ Shared secret+  -> (Word64, Word64)   -- ^ Valid counter range, before and after ideal+  -> UTCTime            -- ^ Time of TOTP+  -> Word64             -- ^ Time range in seconds+  -> Word               -- ^ Numer of digits in a password+  -> Word32             -- ^ Password given by user+  -> Bool               -- ^ True if password is valid totpCheck alg secr rng time period len pass =     let counters = totpCounterRange rng time period         passwds = map (\c -> hotp alg secr c len) counters@@ -181,9 +184,10 @@  -} -totpCounter :: UTCTime          -- ^ Time of totp-            -> Word64           -- ^ Period duration in seconds-            -> Word64           -- ^ Resulting counter+totpCounter+  :: UTCTime     -- ^ Time of totp+  -> Word64      -- ^ Time range in seconds+  -> Word64      -- ^ Resulting counter totpCounter time period =     let timePOSIX = floor $ utcTimeToPOSIXSeconds time     in timePOSIX `div` period@@ -219,9 +223,10 @@ RFC recommends avoiding excessively large values for counter ranges. -} -counterRange :: (Word64, Word64) -- ^ Number of counters before and after ideal-             -> Word64           -- ^ Ideal counter value-             -> [Word64]+counterRange+  :: (Word64, Word64) -- ^ Number of counters before and after ideal+  -> Word64           -- ^ Ideal counter value+  -> [Word64] counterRange (tolow', tohigh') ideal =     let tolow = min 500 tolow'         tohigh = min 499 tohigh'