{-# LANGUAGE OverloadedStrings #-}
module Crypto.G3P.V2.Foxtrot where
import Data.ByteString (ByteString)
import qualified Data.ByteString as B
import Data.Function((&))
import Data.Word
import Data.Vector(Vector)
import qualified Data.Vector as V
import Crypto.G3P.BCrypt (bcryptXsFree)
import Crypto.PHKDF
import Crypto.Encoding.PHKDF (takeBs, nullBuffer)
import Network.ByteOrder(bytestring64)
data G3PFoxtrotSalt = G3PFoxtrotSalt
{ G3PFoxtrotSalt -> HmacKey
g3pFoxtrotSalt_key :: !HmacKey
, G3PFoxtrotSalt -> ByteString
g3pFoxtrotSalt_longTag :: !ByteString
, G3PFoxtrotSalt -> Vector ByteString
g3pFoxtrotSalt_contextTags :: !(Vector ByteString)
, G3PFoxtrotSalt -> ByteString
g3pFoxtrotSalt_domainTag :: !ByteString
, G3PFoxtrotSalt -> Word32
g3pFoxtrotSalt_bcryptRounds :: !Word32
}
g3pFoxtrot
:: (Foldable f, Foldable g)
=> G3PFoxtrotSalt
-> f ByteString
-> g ByteString
-> Word32
-> ByteString
g3pFoxtrot :: forall (f :: * -> *) (g :: * -> *).
(Foldable f, Foldable g) =>
G3PFoxtrotSalt
-> f ByteString -> g ByteString -> Word32 -> ByteString
g3pFoxtrot G3PFoxtrotSalt
salt f ByteString
inputs = g ByteString -> Word32 -> ByteString
forall {f :: * -> *}.
Foldable f =>
f ByteString -> Word32 -> ByteString
doTweak
where
foxtrot :: ByteString
foxtrot = ByteString
"G3Pb2 foxtrot"
key :: HmacKey
key = G3PFoxtrotSalt -> HmacKey
g3pFoxtrotSalt_key G3PFoxtrotSalt
salt
longTag :: ByteString
longTag = G3PFoxtrotSalt -> ByteString
g3pFoxtrotSalt_longTag G3PFoxtrotSalt
salt
contextTags :: Vector ByteString
contextTags = G3PFoxtrotSalt -> Vector ByteString
g3pFoxtrotSalt_contextTags G3PFoxtrotSalt
salt
domainTag :: ByteString
domainTag = G3PFoxtrotSalt -> ByteString
g3pFoxtrotSalt_domainTag G3PFoxtrotSalt
salt
rounds :: Word32
rounds = G3PFoxtrotSalt -> Word32
g3pFoxtrotSalt_bcryptRounds G3PFoxtrotSalt
salt
spark :: HmacKeyPrefixed
spark =
HmacKey -> PhkdfCtx
phkdfCtx_init HmacKey
key PhkdfCtx -> (PhkdfCtx -> PhkdfCtx) -> PhkdfCtx
forall a b. a -> (a -> b) -> b
&
ByteString -> PhkdfCtx -> PhkdfCtx
phkdfCtx_feedArg ByteString
foxtrot PhkdfCtx -> (PhkdfCtx -> PhkdfCtx) -> PhkdfCtx
forall a b. a -> (a -> b) -> b
&
f ByteString -> PhkdfCtx -> PhkdfCtx
forall (f :: * -> *).
Foldable f =>
f ByteString -> PhkdfCtx -> PhkdfCtx
phkdfCtx_feedArgs f ByteString
inputs PhkdfCtx -> (PhkdfCtx -> HmacKeyPrefixed) -> HmacKeyPrefixed
forall a b. a -> (a -> b) -> b
&
(Int -> ByteString) -> PhkdfCtx -> HmacKeyPrefixed
phkdfCtx_toHmacKeyPrefixed ([ByteString] -> ByteString
B.concat ([ByteString] -> ByteString)
-> (Int -> [ByteString]) -> Int -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int64 -> [ByteString] -> [ByteString])
-> [ByteString] -> Int64 -> [ByteString]
forall a b c. (a -> b -> c) -> b -> a -> c
flip Int64 -> [ByteString] -> [ByteString]
takeBs [ByteString
domainTag, ByteString
"\x00", ByteString
longTag, ByteString
nullBuffer] (Int64 -> [ByteString]) -> (Int -> Int64) -> Int -> [ByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral)
bcryptName :: ByteString
bcryptName = [ByteString] -> ByteString
B.concat
[ ByteString
"G3Pb2 bcrypt-xs-free"
, Word64 -> ByteString
bytestring64 (Word64
8 Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
* Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteString -> Int
B.length ByteString
longTag))
]
(Int
_tagPos, HmacKeyPrefixed
seed) =
(ByteString -> ByteString)
-> ByteString
-> Vector ByteString
-> ByteString
-> Vector ByteString
-> ByteString
-> Word32
-> HmacKeyPrefixed
-> (Int, HmacKeyPrefixed)
forall (f :: * -> *) a.
Foldable f =>
(a -> ByteString)
-> ByteString
-> f a
-> ByteString
-> f a
-> ByteString
-> Word32
-> HmacKeyPrefixed
-> (Int, HmacKeyPrefixed)
bcryptXsFree ByteString -> ByteString
forall a. a -> a
id ByteString
bcryptName Vector ByteString
forall a. Vector a
V.empty ByteString
longTag Vector ByteString
contextTags ByteString
domainTag
Word32
rounds HmacKeyPrefixed
spark
sprout :: PhkdfCtx
sprout =
ByteString -> HmacKeyPrefixed -> PhkdfCtx
phkdfCtx_initPrefixed ([ByteString] -> ByteString
B.concat ([ByteString] -> ByteString) -> [ByteString] -> ByteString
forall a b. (a -> b) -> a -> b
$ Int64 -> [ByteString] -> [ByteString]
takeBs Int64
32 [ByteString
domainTag, ByteString
"\x00", ByteString
foxtrot, ByteString
nullBuffer]) HmacKeyPrefixed
seed PhkdfCtx -> (PhkdfCtx -> PhkdfCtx) -> PhkdfCtx
forall a b. a -> (a -> b) -> b
&
Vector ByteString -> PhkdfCtx -> PhkdfCtx
forall (f :: * -> *).
Foldable f =>
f ByteString -> PhkdfCtx -> PhkdfCtx
phkdfCtx_feedArgs Vector ByteString
contextTags
doTweak :: f ByteString -> Word32 -> ByteString
doTweak f ByteString
tweak Word32
counter =
f ByteString -> PhkdfCtx -> PhkdfCtx
forall (f :: * -> *).
Foldable f =>
f ByteString -> PhkdfCtx -> PhkdfCtx
phkdfCtx_feedArgs f ByteString
tweak PhkdfCtx
sprout PhkdfCtx -> (PhkdfCtx -> ByteString) -> ByteString
forall a b. a -> (a -> b) -> b
&
(Int -> ByteString)
-> Word32 -> ByteString -> PhkdfCtx -> ByteString
phkdfCtx_finalize ([ByteString] -> ByteString
B.concat ([ByteString] -> ByteString)
-> (Int -> [ByteString]) -> Int -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int64 -> [ByteString] -> [ByteString])
-> [ByteString] -> Int64 -> [ByteString]
forall a b c. (a -> b -> c) -> b -> a -> c
flip Int64 -> [ByteString] -> [ByteString]
takeBs ([ByteString] -> [ByteString]
forall a. HasCallStack => [a] -> [a]
cycle [ByteString
domainTag, ByteString
"\x00"]) (Int64 -> [ByteString]) -> (Int -> Int64) -> Int -> [ByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral) Word32
counter ByteString
domainTag
g3pTango
:: (Foldable f)
=> HmacKey
-> f ByteString
-> Word32
-> ByteString
-> ByteString
g3pTango :: forall (f :: * -> *).
Foldable f =>
HmacKey -> f ByteString -> Word32 -> ByteString -> ByteString
g3pTango HmacKey
key f ByteString
inputs Word32
counter ByteString
domainTag = ByteString
out
where
tango :: ByteString
tango = ByteString
"G3Pb2 tango"
out :: ByteString
out =
HmacKey -> PhkdfCtx
phkdfCtx_init HmacKey
key PhkdfCtx -> (PhkdfCtx -> PhkdfCtx) -> PhkdfCtx
forall a b. a -> (a -> b) -> b
&
ByteString -> PhkdfCtx -> PhkdfCtx
phkdfCtx_feedArg ByteString
tango PhkdfCtx -> (PhkdfCtx -> PhkdfCtx) -> PhkdfCtx
forall a b. a -> (a -> b) -> b
&
f ByteString -> PhkdfCtx -> PhkdfCtx
forall (f :: * -> *).
Foldable f =>
f ByteString -> PhkdfCtx -> PhkdfCtx
phkdfCtx_feedArgs f ByteString
inputs PhkdfCtx -> (PhkdfCtx -> ByteString) -> ByteString
forall a b. a -> (a -> b) -> b
&
(Int -> ByteString)
-> Word32 -> ByteString -> PhkdfCtx -> ByteString
phkdfCtx_finalize ([ByteString] -> ByteString
B.concat ([ByteString] -> ByteString)
-> (Int -> [ByteString]) -> Int -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int64 -> [ByteString] -> [ByteString])
-> [ByteString] -> Int64 -> [ByteString]
forall a b c. (a -> b -> c) -> b -> a -> c
flip Int64 -> [ByteString] -> [ByteString]
takeBs ([ByteString] -> [ByteString]
forall a. HasCallStack => [a] -> [a]
cycle [ByteString
domainTag, ByteString
"\x00"]) (Int64 -> [ByteString]) -> (Int -> Int64) -> Int -> [ByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral) Word32
counter ByteString
domainTag