mirror of https://github.com/voidlizard/hbs2
new encryption format
This commit is contained in:
parent
be55aa55e7
commit
f3a4082099
|
@ -1,5 +1,7 @@
|
||||||
{-# Language TemplateHaskell #-}
|
{-# Language TemplateHaskell #-}
|
||||||
{-# Language DeriveFunctor #-}
|
{-# Language DeriveFunctor #-}
|
||||||
|
{-# Language PatternSynonyms #-}
|
||||||
|
{-# Language ViewPatterns #-}
|
||||||
module HBS2.Merkle where
|
module HBS2.Merkle where
|
||||||
|
|
||||||
import HBS2.Prelude
|
import HBS2.Prelude
|
||||||
|
@ -14,12 +16,15 @@ import Data.Data
|
||||||
import Data.Foldable (forM_, traverse_)
|
import Data.Foldable (forM_, traverse_)
|
||||||
import Data.List qualified as List
|
import Data.List qualified as List
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
|
import Data.Word
|
||||||
import GHC.Generics
|
import GHC.Generics
|
||||||
import Lens.Micro.Platform
|
import Lens.Micro.Platform
|
||||||
import Control.Monad.Trans.Maybe
|
import Control.Monad.Trans.Maybe
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
import Prettyprinter
|
import Prettyprinter
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
newtype MerkleHash = MerkleHash { fromMerkleHash :: Hash HbSync }
|
newtype MerkleHash = MerkleHash { fromMerkleHash :: Hash HbSync }
|
||||||
deriving newtype (Eq,Ord,IsString,Pretty)
|
deriving newtype (Eq,Ord,IsString,Pretty)
|
||||||
deriving stock (Data,Generic)
|
deriving stock (Data,Generic)
|
||||||
|
@ -97,14 +102,33 @@ instance Serialise a => Serialise (MTreeAnn a)
|
||||||
data MerkleEncryptionType
|
data MerkleEncryptionType
|
||||||
deriving stock (Data)
|
deriving stock (Data)
|
||||||
|
|
||||||
|
data EncryptGroupNaClSymmOpts =
|
||||||
|
EncryptGroupNaClSymmBlockSIP (Word64, Word64)
|
||||||
|
deriving stock (Eq,Ord,Show,Generic,Data)
|
||||||
|
|
||||||
|
instance Serialise EncryptGroupNaClSymmOpts
|
||||||
|
|
||||||
data MTreeEncryption
|
data MTreeEncryption
|
||||||
= NullEncryption
|
= NullEncryption
|
||||||
| CryptAccessKeyNaClAsymm (Hash HbSync)
|
| CryptAccessKeyNaClAsymm (Hash HbSync)
|
||||||
| EncryptGroupNaClSymm (Hash HbSync) ByteString
|
| EncryptGroupNaClSymm1 (Hash HbSync) ByteString
|
||||||
|
| EncryptGroupNaClSymm2 EncryptGroupNaClSymmOpts (Hash HbSync) ByteString
|
||||||
deriving stock (Eq,Generic,Data,Show)
|
deriving stock (Eq,Generic,Data,Show)
|
||||||
|
|
||||||
instance Serialise MTreeEncryption
|
instance Serialise MTreeEncryption
|
||||||
|
|
||||||
|
pattern EncryptGroupNaClSymm :: Hash HbSync -> ByteString -> MTreeEncryption
|
||||||
|
pattern EncryptGroupNaClSymm a b <- ( isEncryptGroupNaClSymm -> Just (a, b) ) where
|
||||||
|
EncryptGroupNaClSymm a b = EncryptGroupNaClSymm1 a b
|
||||||
|
|
||||||
|
isEncryptGroupNaClSymm :: MTreeEncryption
|
||||||
|
-> Maybe (Hash HbSync, ByteString)
|
||||||
|
isEncryptGroupNaClSymm = \case
|
||||||
|
EncryptGroupNaClSymm2 _ a b -> Just (a,b)
|
||||||
|
EncryptGroupNaClSymm1 a b -> Just (a,b)
|
||||||
|
_ -> Nothing
|
||||||
|
|
||||||
|
|
||||||
data MTree a = MNode MNodeData [Hash HbSync] | MLeaf a
|
data MTree a = MNode MNodeData [Hash HbSync] | MLeaf a
|
||||||
deriving stock (Generic,Data,Show)
|
deriving stock (Generic,Data,Show)
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
{-# OPTIONS_GHC -fno-warn-orphans #-}
|
{-# OPTIONS_GHC -fno-warn-orphans #-}
|
||||||
{-# Language TemplateHaskell #-}
|
|
||||||
{-# Language UndecidableInstances #-}
|
{-# Language UndecidableInstances #-}
|
||||||
{-# Language AllowAmbiguousTypes #-}
|
{-# Language AllowAmbiguousTypes #-}
|
||||||
{-# Language ConstraintKinds #-}
|
{-# Language ConstraintKinds #-}
|
||||||
|
@ -23,6 +22,8 @@ import HBS2.Storage.Operations.ByteString
|
||||||
import HBS2.Storage(Storage(..))
|
import HBS2.Storage(Storage(..))
|
||||||
|
|
||||||
|
|
||||||
|
import Data.ByteArray.Hash qualified as BA
|
||||||
|
import Data.ByteArray.Hash (SipHash(..), SipKey(..))
|
||||||
import Codec.Serialise
|
import Codec.Serialise
|
||||||
import Crypto.KDF.HKDF qualified as HKDF
|
import Crypto.KDF.HKDF qualified as HKDF
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
|
@ -58,6 +59,7 @@ import Data.Bits (xor)
|
||||||
|
|
||||||
type GroupSecretAsymm = Key
|
type GroupSecretAsymm = Key
|
||||||
|
|
||||||
|
|
||||||
-- NOTE: breaking-change
|
-- NOTE: breaking-change
|
||||||
|
|
||||||
-- NOTE: not-a-monoid
|
-- NOTE: not-a-monoid
|
||||||
|
@ -88,6 +90,7 @@ data instance ToEncrypt 'Symm s LBS.ByteString =
|
||||||
, toEncryptData :: Stream (Of LBS.ByteString) IO ()
|
, toEncryptData :: Stream (Of LBS.ByteString) IO ()
|
||||||
, toEncryptGroupKey :: GroupKey 'Symm s
|
, toEncryptGroupKey :: GroupKey 'Symm s
|
||||||
, toEncryptMeta :: AnnMetaData
|
, toEncryptMeta :: AnnMetaData
|
||||||
|
, toEncryptOpts :: Maybe EncryptGroupNaClSymmOpts
|
||||||
}
|
}
|
||||||
deriving (Generic)
|
deriving (Generic)
|
||||||
|
|
||||||
|
@ -219,33 +222,30 @@ instance ( MonadIO m
|
||||||
|
|
||||||
let key0 = HKDF.expand prk nonceS typicalKeyLength & Saltine.decode & fromJust
|
let key0 = HKDF.expand prk nonceS typicalKeyLength & Saltine.decode & fromJust
|
||||||
|
|
||||||
-- NOTE: new-format-and-compatibility
|
let method = case toEncryptOpts source of
|
||||||
-- мы можем:
|
Nothing ->
|
||||||
-- 1. поменять схему и схему вычисления нонсов
|
EncryptGroupNaClSymm1 (fromHashRef gkh) nonceS
|
||||||
-- сделать зависимой от схемы. Вот мы пишем
|
|
||||||
-- её внизу, это ок.
|
Just o@(EncryptGroupNaClSymmBlockSIP{}) ->
|
||||||
-- Минусы: сложнее код, менее локальный
|
EncryptGroupNaClSymm2 o (fromHashRef gkh) nonceS
|
||||||
-- Плюсы: надёжнее
|
|
||||||
-- Совместимость: обратная? старая версия
|
let onBlock (i,bs) = do
|
||||||
-- не будет читать новые блоки.
|
case toEncryptOpts source of
|
||||||
--
|
Just (EncryptGroupNaClSymmBlockSIP (a,b)) -> do
|
||||||
-- 2. сериализовать блок с параметрами
|
let bss = LBS.toStrict bs
|
||||||
-- при чтении: пытаемся десереализовать,
|
let (SipHash sip) = BA.sipHash (SipKey a b) bss
|
||||||
-- как блок (читать голову). если не удаётся
|
let nonceI = nonceFrom (nonce0, i + sip)
|
||||||
-- --- читаем, как байтстроку.
|
let encrypted = SK.secretbox key0 nonceI bss
|
||||||
-- минусы: будет медленнее --- лишняя проверка/попытка
|
pure $ serialise (nonceI, encrypted)
|
||||||
-- десереализации на каждый блок.
|
|
||||||
-- плюсы: более локальные изменения
|
_ -> do
|
||||||
--
|
let nonceI = nonceFrom (nonce0, i)
|
||||||
|
let encrypted = SK.secretbox key0 nonceI (LBS.toStrict bs)
|
||||||
|
pure (LBS.fromStrict encrypted)
|
||||||
|
|
||||||
hashes' <- liftIO $ toEncryptData source
|
hashes' <- liftIO $ toEncryptData source
|
||||||
& S.zip (S.enumFrom (1 :: Word64) )
|
& S.zip (S.enumFrom (1 :: Word64) )
|
||||||
& S.mapM ( \(i,bs) -> do
|
& S.mapM onBlock
|
||||||
let nonceI = nonceFrom (nonce0, i)
|
|
||||||
let encrypted = SK.secretbox key0 nonceI (LBS.toStrict bs)
|
|
||||||
pure (LBS.fromStrict encrypted)
|
|
||||||
)
|
|
||||||
|
|
||||||
& S.mapM (enqueueBlock sto)
|
& S.mapM (enqueueBlock sto)
|
||||||
& S.map (fmap HashRef)
|
& S.map (fmap HashRef)
|
||||||
& S.toList_
|
& S.toList_
|
||||||
|
@ -264,11 +264,13 @@ instance ( MonadIO m
|
||||||
|
|
||||||
tree <- maybe (throwError StorageError) pure root
|
tree <- maybe (throwError StorageError) pure root
|
||||||
|
|
||||||
let ann = MTreeAnn (toEncryptMeta source) (EncryptGroupNaClSymm (fromHashRef gkh) nonceS) tree
|
let ann = MTreeAnn (toEncryptMeta source) method tree
|
||||||
|
|
||||||
putBlock sto (serialise ann) >>= maybe (throwError StorageError) pure
|
putBlock sto (serialise ann) >>= maybe (throwError StorageError) pure
|
||||||
|
|
||||||
|
|
||||||
|
data EncMethod = Method1 | Method2
|
||||||
|
|
||||||
instance ( MonadIO m
|
instance ( MonadIO m
|
||||||
, MonadError OperationError m
|
, MonadError OperationError m
|
||||||
, h ~ HbSync
|
, h ~ HbSync
|
||||||
|
@ -279,7 +281,7 @@ instance ( MonadIO m
|
||||||
|
|
||||||
data instance TreeKey (ToDecrypt 'Symm sch ByteString) =
|
data instance TreeKey (ToDecrypt 'Symm sch ByteString) =
|
||||||
ToDecryptBS [KeyringEntry sch] (Hash HbSync)
|
ToDecryptBS [KeyringEntry sch] (Hash HbSync)
|
||||||
| ToDecryptBS2 (GroupKey 'Symm sch) B8.ByteString [KeyringEntry sch] (MTree [HashRef])
|
| ToDecryptBS2 (GroupKey 'Symm sch) B8.ByteString [KeyringEntry sch] (MTreeAnn [HashRef])
|
||||||
|
|
||||||
type instance ToBlockR (ToDecrypt 'Symm sch ByteString) = ByteString
|
type instance ToBlockR (ToDecrypt 'Symm sch ByteString) = ByteString
|
||||||
type instance ReadResult (ToDecrypt 'Symm sch ByteString) = ByteString
|
type instance ReadResult (ToDecrypt 'Symm sch ByteString) = ByteString
|
||||||
|
@ -297,23 +299,33 @@ instance ( MonadIO m
|
||||||
let nonce0 = nonceFrom @SK.Nonce nonceS
|
let nonce0 = nonceFrom @SK.Nonce nonceS
|
||||||
|
|
||||||
hashes <- S.toList_ $
|
hashes <- S.toList_ $
|
||||||
walkMerkleTree tree (lift . getBlock sto) $ \case
|
walkMerkleTree (_mtaTree tree) (lift . getBlock sto) $ \case
|
||||||
Left{} -> throwError MissedBlockError
|
Left{} -> throwError MissedBlockError
|
||||||
Right hrr -> S.each hrr
|
Right hrr -> S.each hrr
|
||||||
|
|
||||||
|
|
||||||
|
method <- case _mtaCrypt tree of
|
||||||
|
EncryptGroupNaClSymm1{} -> pure Method1
|
||||||
|
EncryptGroupNaClSymm2 (EncryptGroupNaClSymmBlockSIP _) _ _ -> pure Method2
|
||||||
|
_ -> throwError UnsupportedFormat
|
||||||
|
|
||||||
ss <- forM (zip [1..] hashes) $ \(i :: Word64,h) -> do
|
ss <- forM (zip [1..] hashes) $ \(i :: Word64,h) -> do
|
||||||
blk <- getBlock sto (fromHashRef h) >>= maybe (throwError MissedBlockError) pure
|
blk <- getBlock sto (fromHashRef h) >>= maybe (throwError MissedBlockError) pure
|
||||||
|
|
||||||
let nonceI = nonceFrom (nonce0, i)
|
case method of
|
||||||
|
Method1 -> do
|
||||||
let unboxed = SK.secretboxOpen key0 nonceI (LBS.toStrict blk)
|
let nonceI = nonceFrom (nonce0, i)
|
||||||
|
let unboxed = SK.secretboxOpen key0 nonceI (LBS.toStrict blk)
|
||||||
maybe1 unboxed (throwError DecryptionError) (pure . LBS.fromStrict)
|
maybe1 unboxed (throwError DecryptionError) (pure . LBS.fromStrict)
|
||||||
|
Method2 -> do
|
||||||
|
(nonce, bss) <- deserialiseOrFail @(SK.Nonce, N.ByteString) blk
|
||||||
|
& either (const $ throwError UnsupportedFormat) pure
|
||||||
|
let unboxed = SK.secretboxOpen key0 nonce bss
|
||||||
|
maybe1 unboxed (throwError DecryptionError) (pure . LBS.fromStrict)
|
||||||
|
|
||||||
-- FIXME: stream-unboxed-blocks
|
-- FIXME: stream-unboxed-blocks
|
||||||
pure $ mconcat ss
|
pure $ mconcat ss
|
||||||
|
|
||||||
|
|
||||||
where
|
where
|
||||||
|
|
||||||
decryptDataFrom = \case
|
decryptDataFrom = \case
|
||||||
|
@ -328,7 +340,7 @@ instance ( MonadIO m
|
||||||
let what = tryDetect h bs
|
let what = tryDetect h bs
|
||||||
|
|
||||||
let tree' = case what of
|
let tree' = case what of
|
||||||
MerkleAnn ann@(MTreeAnn {_mtaCrypt = EncryptGroupNaClSymm g n}) -> Just (_mtaTree ann, (g,n))
|
MerkleAnn ann@(MTreeAnn {_mtaCrypt = EncryptGroupNaClSymm g n}) -> Just (ann, (g,n))
|
||||||
_ -> Nothing
|
_ -> Nothing
|
||||||
|
|
||||||
(tree, (gkh,nonceS)) <- maybe1 tree' (throwError UnsupportedFormat) pure
|
(tree, (gkh,nonceS)) <- maybe1 tree' (throwError UnsupportedFormat) pure
|
||||||
|
|
|
@ -453,7 +453,7 @@ storeObjectRPC True repo meta bs = do
|
||||||
& LBS.toStrict
|
& LBS.toStrict
|
||||||
|
|
||||||
let bsStream = readChunkedBS bs defBlockSize
|
let bsStream = readChunkedBS bs defBlockSize
|
||||||
let source = ToEncryptSymmBS gks nonce bsStream gk0 (ShortMetadata txt)
|
let source = ToEncryptSymmBS gks nonce bsStream gk0 (ShortMetadata txt) Nothing
|
||||||
|
|
||||||
h <- runExceptT (writeAsMerkle sto source) >>= either (const cantWriteMerkle) pure
|
h <- runExceptT (writeAsMerkle sto source) >>= either (const cantWriteMerkle) pure
|
||||||
|
|
||||||
|
|
|
@ -257,7 +257,7 @@ importRefLogNew opts ref = runResourceT do
|
||||||
|
|
||||||
(src, enc) <- case something of
|
(src, enc) <- case something of
|
||||||
|
|
||||||
MerkleAnn (MTreeAnn _ sc@(EncryptGroupNaClSymm g nonce) tree) -> do
|
MerkleAnn ann@(MTreeAnn _ sc@(EncryptGroupNaClSymm g nonce) tree) -> do
|
||||||
|
|
||||||
gk10' <- runExceptT $ readFromMerkle sto (SimpleKey g)
|
gk10' <- runExceptT $ readFromMerkle sto (SimpleKey g)
|
||||||
|
|
||||||
|
@ -271,7 +271,7 @@ importRefLogNew opts ref = runResourceT do
|
||||||
let gk1 = mconcat $ gk10 : gk11
|
let gk1 = mconcat $ gk10 : gk11
|
||||||
|
|
||||||
-- elbs <- runExceptT $ readFromMerkle sto (ToDecryptBS decrypt (fromHashRef h))
|
-- elbs <- runExceptT $ readFromMerkle sto (ToDecryptBS decrypt (fromHashRef h))
|
||||||
elbs <- runExceptT $ readFromMerkle sto (ToDecryptBS2 gk1 nonce decrypt tree)
|
elbs <- runExceptT $ readFromMerkle sto (ToDecryptBS2 gk1 nonce decrypt ann)
|
||||||
|
|
||||||
case elbs of
|
case elbs of
|
||||||
Left{} -> do
|
Left{} -> do
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
{-# Language RecordWildCards #-}
|
{-# Language RecordWildCards #-}
|
||||||
|
{-# Language PatternSynonyms, ViewPatterns #-}
|
||||||
module Main where
|
module Main where
|
||||||
|
|
||||||
import HBS2.Prelude
|
import HBS2.Prelude
|
||||||
|
@ -43,6 +44,27 @@ a1Str = lens g s
|
||||||
-- новая версия: должна понимать и старую, и новую голову.
|
-- новая версия: должна понимать и старую, и новую голову.
|
||||||
--
|
--
|
||||||
|
|
||||||
|
|
||||||
|
data W = A | B0 | B1 Bool
|
||||||
|
|
||||||
|
isB a = case a of
|
||||||
|
B0 -> True
|
||||||
|
B1 _ -> True
|
||||||
|
_ -> False
|
||||||
|
|
||||||
|
-- -- Определяем паттерн-синоним для B, который будет сопоставлять B0 и B1
|
||||||
|
pattern B :: Bool -> W
|
||||||
|
pattern B b <- (isB -> b)
|
||||||
|
|
||||||
|
{-# COMPLETE A, B #-}
|
||||||
|
|
||||||
|
-- -- Функция test использует паттерн B для сопоставления с образцом
|
||||||
|
test :: W -> String
|
||||||
|
test w = case w of
|
||||||
|
B val -> "Match B with value " ++ show val
|
||||||
|
A -> "Match A"
|
||||||
|
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = do
|
main = do
|
||||||
print "1"
|
print "1"
|
||||||
|
|
|
@ -380,7 +380,7 @@ runStore opts ss = runResourceT do
|
||||||
|
|
||||||
let segments = readChunked fh (fromIntegral defBlockSize)
|
let segments = readChunked fh (fromIntegral defBlockSize)
|
||||||
|
|
||||||
let source = ToEncryptSymmBS gks nonce segments gk NoMetaData
|
let source = ToEncryptSymmBS gks nonce segments gk NoMetaData Nothing
|
||||||
|
|
||||||
r <- runExceptT $ writeAsMerkle ss source
|
r <- runExceptT $ writeAsMerkle ss source
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue