feat(allocations): switch to csprng
This commit is contained in:
parent
11c86bb5fa
commit
3ea7371465
@ -21,6 +21,7 @@ Allocation -- attributes with prefix staff- affect lecturers only, but are invis
|
|||||||
registerByCourse UTCTime Maybe -- course registration dates are ignored until this day has passed or always prohibited
|
registerByCourse UTCTime Maybe -- course registration dates are ignored until this day has passed or always prohibited
|
||||||
overrideDeregister UTCTime Maybe -- course deregistration enforced to be this date, i.e. students may disenrol from course after or never
|
overrideDeregister UTCTime Maybe -- course deregistration enforced to be this date, i.e. students may disenrol from course after or never
|
||||||
-- overrideVisible not needed, since courses are always visible
|
-- overrideVisible not needed, since courses are always visible
|
||||||
|
matchingSeed ByteString default=''
|
||||||
TermSchoolAllocationShort term school shorthand -- shorthand must be unique within school and semester
|
TermSchoolAllocationShort term school shorthand -- shorthand must be unique within school and semester
|
||||||
TermSchoolAllocationName term school name -- name must be unique within school and semester
|
TermSchoolAllocationName term school name -- name must be unique within school and semester
|
||||||
deriving Show Eq Ord Generic
|
deriving Show Eq Ord Generic
|
||||||
|
|||||||
19
src/Crypto/Random/Instances.hs
Normal file
19
src/Crypto/Random/Instances.hs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{-# OPTIONS_GHC -fno-warn-orphans #-}
|
||||||
|
|
||||||
|
module Crypto.Random.Instances
|
||||||
|
(
|
||||||
|
) where
|
||||||
|
|
||||||
|
import ClassyPrelude
|
||||||
|
|
||||||
|
import Crypto.Random
|
||||||
|
import System.Random (RandomGen(..))
|
||||||
|
|
||||||
|
import qualified Data.ByteArray as BA
|
||||||
|
|
||||||
|
import Data.Bits
|
||||||
|
|
||||||
|
|
||||||
|
instance RandomGen ChaChaDRG where
|
||||||
|
next g = withRandomBytes g (finiteBitSize (maxBound :: Int) `div` 8) (foldr (\x acc -> acc `shiftL` 8 .|. fromIntegral x) zeroBits . BA.unpack @BA.Bytes)
|
||||||
|
split g = withDRG g drgNew
|
||||||
@ -115,7 +115,7 @@ postAComputeR tid ssh ash = do
|
|||||||
|
|
||||||
formResult computeFormRes $ \AllocationComputeForm{..} -> do
|
formResult computeFormRes $ \AllocationComputeForm{..} -> do
|
||||||
now <- liftIO getCurrentTime
|
now <- liftIO getCurrentTime
|
||||||
(allocFp, allocMatching, allocLog) <- computeAllocation aId acfRestrictCourses
|
(allocFp, allocMatching, allocLog) <- computeAllocation aEnt acfRestrictCourses
|
||||||
tellSessionJson SessionAllocationResults . SessionDataAllocationResults $
|
tellSessionJson SessionAllocationResults . SessionDataAllocationResults $
|
||||||
Map.singleton (tid, ssh, ash) (now, allocFp, allocMatching, allocLog)
|
Map.singleton (tid, ssh, ash) (now, allocFp, allocMatching, allocLog)
|
||||||
addMessageI Success MsgAllocationComputed
|
addMessageI Success MsgAllocationComputed
|
||||||
|
|||||||
@ -24,7 +24,10 @@ import qualified Data.Vector as Vector
|
|||||||
import Data.Vector.Lens (vector)
|
import Data.Vector.Lens (vector)
|
||||||
import qualified Data.Set as Set
|
import qualified Data.Set as Set
|
||||||
|
|
||||||
import System.Random (mkStdGen)
|
import qualified Data.Binary as Binary
|
||||||
|
import Crypto.Hash.Algorithms (SHAKE256)
|
||||||
|
import Crypto.Random (drgNewSeed, seedFromBinary)
|
||||||
|
import Crypto.Error (onCryptoFailure)
|
||||||
|
|
||||||
import Utils.Allocation
|
import Utils.Allocation
|
||||||
|
|
||||||
@ -33,7 +36,8 @@ import qualified Data.Conduit.List as C
|
|||||||
import Data.Generics.Product.Param
|
import Data.Generics.Product.Param
|
||||||
|
|
||||||
import qualified Crypto.Hash as Crypto
|
import qualified Crypto.Hash as Crypto
|
||||||
import qualified Data.Binary as Binary
|
|
||||||
|
import Language.Haskell.TH (nameBase)
|
||||||
|
|
||||||
|
|
||||||
data MatchingExcludedReason
|
data MatchingExcludedReason
|
||||||
@ -81,13 +85,13 @@ sinkAllocationPriorities allocId = fmap getSum . C.foldMapM . ifoldMapM $ \matr
|
|||||||
E.&&. user E.^. UserMatrikelnummer E.==. E.val (Just matr)
|
E.&&. user E.^. UserMatrikelnummer E.==. E.val (Just matr)
|
||||||
|
|
||||||
|
|
||||||
computeAllocation :: AllocationId
|
computeAllocation :: Entity Allocation
|
||||||
-> Maybe (Set CourseId) -- ^ Optionally restrict allocation to only consider the given courses
|
-> Maybe (Set CourseId) -- ^ Optionally restrict allocation to only consider the given courses
|
||||||
-> DB ( AllocationFingerprint
|
-> DB ( AllocationFingerprint
|
||||||
, Set (UserId, CourseId)
|
, Set (UserId, CourseId)
|
||||||
, Seq MatchingLogRun
|
, Seq MatchingLogRun
|
||||||
)
|
)
|
||||||
computeAllocation allocId cRestr = do
|
computeAllocation (Entity allocId Allocation{allocationMatchingSeed}) cRestr = do
|
||||||
allocations <- selectList [ CourseParticipantAllocated ==. Just allocId ] []
|
allocations <- selectList [ CourseParticipantAllocated ==. Just allocId ] []
|
||||||
let allocations' = allocations
|
let allocations' = allocations
|
||||||
& map ((, Sum 1) . courseParticipantUser . entityVal)
|
& map ((, Sum 1) . courseParticipantUser . entityVal)
|
||||||
@ -193,10 +197,12 @@ computeAllocation allocId cRestr = do
|
|||||||
= id
|
= id
|
||||||
|
|
||||||
let
|
let
|
||||||
fingerprint :: AllocationFingerprint
|
inputs = Binary.encode (users'', capacities, preferences, gradeScale, gradeOrdinalPlaces)
|
||||||
fingerprint = Crypto.hash . toStrict $ Binary.encode (users'', capacities, preferences, gradeScale, gradeOrdinalPlaces)
|
|
||||||
|
|
||||||
g = mkStdGen $ hash fingerprint
|
fingerprint :: AllocationFingerprint
|
||||||
|
fingerprint = Crypto.hashlazy inputs
|
||||||
|
|
||||||
|
g = onCryptoFailure (\_ -> error "Could not create DRG") id . fmap drgNewSeed . seedFromBinary $ kmaclazy @(SHAKE256 320) (encodeUtf8 . (pack :: String -> Text) $ nameBase 'computeAllocation) allocationMatchingSeed inputs
|
||||||
|
|
||||||
let
|
let
|
||||||
doAllocationWithout :: Set CourseId -> Writer (Seq (MatchingLog UserId CourseId Natural)) (Set (UserId, CourseId))
|
doAllocationWithout :: Set CourseId -> Writer (Seq (MatchingLog UserId CourseId Natural)) (Set (UserId, CourseId))
|
||||||
|
|||||||
@ -26,10 +26,8 @@ import Data.Time.Clock.POSIX (utcTimeToPOSIXSeconds, posixSecondsToUTCTime)
|
|||||||
|
|
||||||
import qualified Data.Binary as Binary
|
import qualified Data.Binary as Binary
|
||||||
|
|
||||||
import qualified Crypto.MAC.KMAC as KMAC
|
|
||||||
import Crypto.Hash.Algorithms (SHAKE256)
|
import Crypto.Hash.Algorithms (SHAKE256)
|
||||||
|
|
||||||
import qualified Data.ByteString.Lazy as LBS
|
|
||||||
import qualified Data.ByteArray as BA
|
import qualified Data.ByteArray as BA
|
||||||
|
|
||||||
import Language.Haskell.TH
|
import Language.Haskell.TH
|
||||||
@ -94,7 +92,7 @@ memcachedKey :: ( Typeable a
|
|||||||
)
|
)
|
||||||
=> AEAD.Key -> Proxy a -> k -> ByteString
|
=> AEAD.Key -> Proxy a -> k -> ByteString
|
||||||
memcachedKey (Saltine.encode -> kmacKey) p k = Binary.encode k
|
memcachedKey (Saltine.encode -> kmacKey) p k = Binary.encode k
|
||||||
& KMAC.finalize . KMAC.updates (KMAC.initialize @(SHAKE256 256) (encodeUtf8 . tshow $ typeRep p) kmacKey) . LBS.toChunks
|
& kmaclazy @(SHAKE256 256) (encodeUtf8 . tshow $ typeRep p) kmacKey
|
||||||
& BA.convert
|
& BA.convert
|
||||||
|
|
||||||
memcachedByGet :: forall a k m.
|
memcachedByGet :: forall a k m.
|
||||||
|
|||||||
@ -156,8 +156,10 @@ import Yesod.Form.Fields.Instances as Import ()
|
|||||||
import Data.MonoTraversable.Instances as Import ()
|
import Data.MonoTraversable.Instances as Import ()
|
||||||
import Web.Cookie.Instances as Import ()
|
import Web.Cookie.Instances as Import ()
|
||||||
import Network.HTTP.Types.Method.Instances as Import ()
|
import Network.HTTP.Types.Method.Instances as Import ()
|
||||||
|
import Crypto.Random.Instances as Import ()
|
||||||
|
|
||||||
import Crypto.Hash as Import (Digest, SHA3_256)
|
import Crypto.Hash as Import (Digest, SHA3_256)
|
||||||
|
import Crypto.Random as Import (ChaChaDRG, Seed)
|
||||||
|
|
||||||
import Control.Lens as Import
|
import Control.Lens as Import
|
||||||
hiding ( (<.>)
|
hiding ( (<.>)
|
||||||
|
|||||||
18
src/Utils.hs
18
src/Utils.hs
@ -78,6 +78,10 @@ import qualified Data.ByteString.Base64.URL as Base64
|
|||||||
import qualified Crypto.Saltine.Core.SecretBox as SecretBox
|
import qualified Crypto.Saltine.Core.SecretBox as SecretBox
|
||||||
import qualified Crypto.Saltine.Class as Saltine
|
import qualified Crypto.Saltine.Class as Saltine
|
||||||
import qualified Crypto.Data.PKCS7 as PKCS7
|
import qualified Crypto.Data.PKCS7 as PKCS7
|
||||||
|
import Crypto.MAC.KMAC (KMAC, HashSHAKE)
|
||||||
|
import qualified Crypto.MAC.KMAC as KMAC
|
||||||
|
|
||||||
|
import Data.ByteArray (ByteArrayAccess)
|
||||||
|
|
||||||
import Data.Fixed
|
import Data.Fixed
|
||||||
-- import Data.Ratio ((%))
|
-- import Data.Ratio ((%))
|
||||||
@ -963,6 +967,20 @@ encodedSecretBoxOpen ciphertext = do
|
|||||||
sKey <- secretBoxKey
|
sKey <- secretBoxKey
|
||||||
encodedSecretBoxOpen' sKey ciphertext
|
encodedSecretBoxOpen' sKey ciphertext
|
||||||
|
|
||||||
|
|
||||||
|
kmaclazy :: forall a string key ba chunk.
|
||||||
|
( HashSHAKE a
|
||||||
|
, ByteArrayAccess string
|
||||||
|
, ByteArrayAccess key
|
||||||
|
, ByteArrayAccess chunk
|
||||||
|
, LazySequence ba chunk
|
||||||
|
)
|
||||||
|
=> string
|
||||||
|
-> key
|
||||||
|
-> ba
|
||||||
|
-> KMAC a
|
||||||
|
kmaclazy str k = KMAC.finalize . KMAC.updates (KMAC.initialize @a str k) . toChunks
|
||||||
|
|
||||||
-------------
|
-------------
|
||||||
-- Caching --
|
-- Caching --
|
||||||
-------------
|
-------------
|
||||||
|
|||||||
@ -24,6 +24,8 @@ import qualified Data.CaseInsensitive as CI
|
|||||||
|
|
||||||
import qualified Data.Csv as Csv
|
import qualified Data.Csv as Csv
|
||||||
|
|
||||||
|
import Crypto.Random (getRandomBytes)
|
||||||
|
|
||||||
|
|
||||||
testdataDir :: FilePath
|
testdataDir :: FilePath
|
||||||
testdataDir = "testdata"
|
testdataDir = "testdata"
|
||||||
@ -969,6 +971,7 @@ fillDb = do
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
aSeedFunc <- liftIO $ getRandomBytes 40
|
||||||
funAlloc <- insert' Allocation
|
funAlloc <- insert' Allocation
|
||||||
{ allocationName = "Funktionale Zentralanmeldung"
|
{ allocationName = "Funktionale Zentralanmeldung"
|
||||||
, allocationShorthand = "fun"
|
, allocationShorthand = "fun"
|
||||||
@ -986,6 +989,7 @@ fillDb = do
|
|||||||
, allocationRegisterByStaffTo = Nothing
|
, allocationRegisterByStaffTo = Nothing
|
||||||
, allocationRegisterByCourse = Nothing
|
, allocationRegisterByCourse = Nothing
|
||||||
, allocationOverrideDeregister = Just $ termTime True Summer 1 False Monday toMidnight
|
, allocationOverrideDeregister = Just $ termTime True Summer 1 False Monday toMidnight
|
||||||
|
, allocationMatchingSeed = aSeedFunc
|
||||||
}
|
}
|
||||||
insert_ $ AllocationCourse funAlloc pmo 100
|
insert_ $ AllocationCourse funAlloc pmo 100
|
||||||
insert_ $ AllocationCourse funAlloc ffp 2
|
insert_ $ AllocationCourse funAlloc ffp 2
|
||||||
@ -1088,6 +1092,7 @@ fillDb = do
|
|||||||
forM_ (take participants manyUsers') $ \uid ->
|
forM_ (take participants manyUsers') $ \uid ->
|
||||||
void . insert $ CourseParticipant cid uid now Nothing Nothing
|
void . insert $ CourseParticipant cid uid now Nothing Nothing
|
||||||
|
|
||||||
|
aSeedBig <- liftIO $ getRandomBytes 40
|
||||||
bigAlloc <- insert' Allocation
|
bigAlloc <- insert' Allocation
|
||||||
{ allocationName = "Große Zentralanmeldung"
|
{ allocationName = "Große Zentralanmeldung"
|
||||||
, allocationShorthand = "big"
|
, allocationShorthand = "big"
|
||||||
@ -1105,6 +1110,7 @@ fillDb = do
|
|||||||
, allocationRegisterByStaffTo = Nothing
|
, allocationRegisterByStaffTo = Nothing
|
||||||
, allocationRegisterByCourse = Nothing
|
, allocationRegisterByCourse = Nothing
|
||||||
, allocationOverrideDeregister = Just $ termTime True Summer 1 False Monday toMidnight
|
, allocationOverrideDeregister = Just $ termTime True Summer 1 False Monday toMidnight
|
||||||
|
, allocationMatchingSeed = aSeedBig
|
||||||
}
|
}
|
||||||
bigAllocCourses <- forM ([1..40] :: [Int]) $ \n -> do
|
bigAllocCourses <- forM ([1..40] :: [Int]) $ \n -> do
|
||||||
csh <- pack . take 3 <$> getRandomRs ('A', 'Z')
|
csh <- pack . take 3 <$> getRandomRs ('A', 'Z')
|
||||||
|
|||||||
Reference in New Issue
Block a user