diff --git a/src/Tahoe/SDMF/Internal/Keys.hs b/src/Tahoe/SDMF/Internal/Keys.hs index d4f6eaaa008f6c21950f59d2c0fc7758035a76cf..4ba23fe5483f3fb0313c20c20de49df62d592afe 100644 --- a/src/Tahoe/SDMF/Internal/Keys.hs +++ b/src/Tahoe/SDMF/Internal/Keys.hs @@ -20,7 +20,6 @@ import qualified Data.ByteString.Lazy as LB import qualified Data.Text as T import Data.X509 (PrivKey (PrivKeyRSA), PubKey (PubKeyRSA)) import Tahoe.CHK.Crypto (taggedHash, taggedPairHash) -import Tahoe.CHK.Server (StorageServerID) newtype KeyPair = KeyPair {toPrivateKey :: RSA.PrivateKey} deriving newtype (Show) @@ -40,7 +39,7 @@ newtype StorageIndex = StorageIndex {unStorageIndex :: B.ByteString} newtype WriteEnablerMaster = WriteEnablerMaster ByteArray.ScrubbedBytes -data WriteEnabler = WriteEnabler StorageServerID ByteArray.ScrubbedBytes +newtype WriteEnabler = WriteEnabler ByteArray.ScrubbedBytes data Data = Data {unData :: AES128, dataKeyBytes :: ByteArray.ScrubbedBytes} @@ -95,6 +94,7 @@ deriveDataKey :: SDMF_IV -> Read -> Maybe Data deriveDataKey (SDMF_IV iv) r = Data <$> key <*> pure (ByteArray.convert sbs) where + -- XXX taggedPairHash has a bug where it doesn't ever truncate. sbs = B.take keyLength . taggedPairHash keyLength mutableDataKeyTag (B.pack . ByteArray.unpack $ iv) . ByteArray.convert . readKeyBytes $ r key = maybeCryptoError . cipherInit $ sbs @@ -123,6 +123,19 @@ deriveWriteEnablerMaster w = WriteEnablerMaster bs mutableWriteEnablerMasterTag :: B.ByteString mutableWriteEnablerMasterTag = "allmydata_mutable_writekey_to_write_enabler_master_v1" +{- | Derive the "write enabler" secret for a given peer and "write enabler + master" for an SDMF share. +-} +deriveWriteEnabler :: B.ByteString -> WriteEnablerMaster -> WriteEnabler +deriveWriteEnabler peerid (WriteEnablerMaster master) = WriteEnabler bs + where + -- This one shouldn't be truncated. Set the length to the size of sha256d + -- output. + bs = ByteArray.convert . taggedPairHash 32 mutableWriteEnablerTag (ByteArray.convert master) $ peerid + +mutableWriteEnablerTag :: B.ByteString +mutableWriteEnablerTag = "allmydata_mutable_write_enabler_master_and_nodeid_to_write_enabler_v1" + {- | Encode a public key to the Tahoe-LAFS canonical bytes representation - X.509 SubjectPublicKeyInfo of the ASN.1 DER serialization of an RSA PublicKey. diff --git a/src/Tahoe/SDMF/Keys.hs b/src/Tahoe/SDMF/Keys.hs index 7b724d19626def89695df1230f243bc2dc0c9b00..165915612de3689305539139b0c0e53807b323da 100644 --- a/src/Tahoe/SDMF/Keys.hs +++ b/src/Tahoe/SDMF/Keys.hs @@ -8,10 +8,12 @@ import Tahoe.SDMF.Internal.Keys ( Signature (..), StorageIndex (..), Write (..), + WriteEnabler (..), WriteEnablerMaster (..), deriveDataKey, deriveReadKey, deriveStorageIndex, + deriveWriteEnabler, deriveWriteEnablerMaster, deriveWriteKey, toPublicKey, diff --git a/test/Spec.hs b/test/Spec.hs index e0061e9f6d194c61dfd7b73b21eeb737cfd755d5..e185dc49dcb1d803fa8f0b21ec09d97bc8fe549d 100644 --- a/test/Spec.hs +++ b/test/Spec.hs @@ -86,15 +86,20 @@ tests = expectedDataKey = ("bbj67exlrkfcaqutwlgwvukbfe" :: T.Text) expectedStorageIndex = ("cmkuloz2t6fhsh7npxxteba6sq" :: T.Text) expectedWriteEnablerMaster = ("qgptod5dsanfep2kbimvxl2yixndnoks7ndoeamczj7g33gokcvq" :: T.Text) + expectedWriteEnabler = ("bg4ldrgfyiffufltcuttr3cnrmrjfpoxc65qdoqa6d5izkzofl5q" :: T.Text) - -- Derive all the keys. + -- Constants involved in the derivation. These agree with + -- those used to generate the above expected values. (Just iv) = Keys.SDMF_IV <$> makeIV (B.replicate 16 0x42) + peerid = B.replicate 20 0x42 + + -- Derive all the keys. (Just w@(Keys.Write _ derivedWriteKey)) = Keys.deriveWriteKey sigKey (Just r@(Keys.Read _ derivedReadKey)) = Keys.deriveReadKey w (Just (Keys.Data _ derivedDataKey)) = Keys.deriveDataKey iv r (Keys.StorageIndex derivedStorageIndex) = Keys.deriveStorageIndex r - (Keys.WriteEnablerMaster derivedWriteEnablerMaster) = Keys.deriveWriteEnablerMaster w - + wem@(Keys.WriteEnablerMaster derivedWriteEnablerMaster) = Keys.deriveWriteEnablerMaster w + (Keys.WriteEnabler derivedWriteEnabler) = Keys.deriveWriteEnabler peerid wem -- A helper to format a key as text for convenient -- comparison to expected value. fmtKey = T.toLower . encodeBase32Unpadded . ByteArray.convert @@ -124,6 +129,10 @@ tests = "write enabler master: expected /= derived" expectedWriteEnablerMaster (fmtKey derivedWriteEnablerMaster) + assertEqual + "write enabler: expected /= derived" + expectedWriteEnabler + (fmtKey derivedWriteEnabler) , testProperty "Share round-trips through bytes" $ property $ do share <- forAll shares