diff --git a/src/Tahoe/SDMF/Internal/Keys.hs b/src/Tahoe/SDMF/Internal/Keys.hs index 29c017f690e0605a0648527090b36245874ee2c2..d4f6eaaa008f6c21950f59d2c0fc7758035a76cf 100644 --- a/src/Tahoe/SDMF/Internal/Keys.hs +++ b/src/Tahoe/SDMF/Internal/Keys.hs @@ -38,8 +38,9 @@ instance Show Write where data Read = Read {unRead :: AES128, readKeyBytes :: ByteArray.ScrubbedBytes} newtype StorageIndex = StorageIndex {unStorageIndex :: B.ByteString} -newtype WriteEnablerMaster = WriteEnablerMaster B.ByteString -data WriteEnabler = WriteEnabler StorageServerID B.ByteString +newtype WriteEnablerMaster = WriteEnablerMaster ByteArray.ScrubbedBytes + +data WriteEnabler = WriteEnabler StorageServerID ByteArray.ScrubbedBytes data Data = Data {unData :: AES128, dataKeyBytes :: ByteArray.ScrubbedBytes} @@ -97,10 +98,10 @@ deriveDataKey (SDMF_IV iv) r = sbs = B.take keyLength . taggedPairHash keyLength mutableDataKeyTag (B.pack . ByteArray.unpack $ iv) . ByteArray.convert . readKeyBytes $ r key = maybeCryptoError . cipherInit $ sbs --- | Compute the storage index for a given read key for an SDMF share. mutableDataKeyTag :: B.ByteString mutableDataKeyTag = "allmydata_mutable_readkey_to_datakey_v1" +-- | Compute the storage index for a given read key for an SDMF share. deriveStorageIndex :: Read -> StorageIndex deriveStorageIndex r = StorageIndex si where @@ -109,6 +110,19 @@ deriveStorageIndex r = StorageIndex si mutableStorageIndexTag :: B.ByteString mutableStorageIndexTag = "allmydata_mutable_readkey_to_storage_index_v1" +{- | Derive the "write enabler master" secret for a given write key for an + SDMF share. +-} +deriveWriteEnablerMaster :: Write -> WriteEnablerMaster +deriveWriteEnablerMaster w = WriteEnablerMaster bs + where + -- This one shouldn't be truncated. Set the length to the size of sha256d + -- output. + bs = ByteArray.convert . taggedHash 32 mutableWriteEnablerMasterTag . ByteArray.convert . writeKeyBytes $ w + +mutableWriteEnablerMasterTag :: B.ByteString +mutableWriteEnablerMasterTag = "allmydata_mutable_writekey_to_write_enabler_master_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 75a503bb0fe004711cec016738f5772075444f69..7b724d19626def89695df1230f243bc2dc0c9b00 100644 --- a/src/Tahoe/SDMF/Keys.hs +++ b/src/Tahoe/SDMF/Keys.hs @@ -8,9 +8,11 @@ import Tahoe.SDMF.Internal.Keys ( Signature (..), StorageIndex (..), Write (..), + WriteEnablerMaster (..), deriveDataKey, deriveReadKey, deriveStorageIndex, + deriveWriteEnablerMaster, deriveWriteKey, toPublicKey, ) diff --git a/test/Spec.hs b/test/Spec.hs index cb08caaff95a66e0c852e074bcfacfd88296aa23..e0061e9f6d194c61dfd7b73b21eeb737cfd755d5 100644 --- a/test/Spec.hs +++ b/test/Spec.hs @@ -85,6 +85,7 @@ tests = expectedReadKey = ("6ir6husgx6ubro3tbimmzskqri" :: T.Text) expectedDataKey = ("bbj67exlrkfcaqutwlgwvukbfe" :: T.Text) expectedStorageIndex = ("cmkuloz2t6fhsh7npxxteba6sq" :: T.Text) + expectedWriteEnablerMaster = ("qgptod5dsanfep2kbimvxl2yixndnoks7ndoeamczj7g33gokcvq" :: T.Text) -- Derive all the keys. (Just iv) = Keys.SDMF_IV <$> makeIV (B.replicate 16 0x42) @@ -92,6 +93,7 @@ tests = (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 -- A helper to format a key as text for convenient -- comparison to expected value. @@ -103,21 +105,25 @@ tests = -- instance so we go the other way. We're not worried about -- the safety of these test-only keys anyway. assertEqual - "expected writekey /= derived writekey" + "writekey: expected /= derived" expectedWriteKey (fmtKey derivedWriteKey) assertEqual - "expected readkey /= derived readkey" + "readkey: expected /= derived" expectedReadKey (fmtKey derivedReadKey) assertEqual - "expected datakey /= derived datakey" + "datakey: expected /= derived" expectedDataKey (fmtKey derivedDataKey) assertEqual - "expected storage index /= derived storage index" + "storage index: expected /= derived" expectedStorageIndex (T.toLower . encodeBase32Unpadded $ derivedStorageIndex) + assertEqual + "write enabler master: expected /= derived" + expectedWriteEnablerMaster + (fmtKey derivedWriteEnablerMaster) , testProperty "Share round-trips through bytes" $ property $ do share <- forAll shares diff --git a/test/expected_values.py b/test/expected_values.py index 8ad03d95cf546650be06aa582bf0d00bed52053e..31d18d9e3a05396116d406689947cfee020a7238 100644 --- a/test/expected_values.py +++ b/test/expected_values.py @@ -4,30 +4,32 @@ from allmydata.crypto import rsa from allmydata.mutable.common import derive_mutable_keys from allmydata.util import base32 -from allmydata.util.hashutil import ( - ssk_readkey_hash, - ssk_readkey_data_hash, - ssk_storage_index_hash, -) +from allmydata.util import hashutil # Arbitrarily select an IV. iv = b"\x42" * 16 +# And "peer id" +peerid = b"\x42" * 20 with open("data/rsa-privkey-0.der", "rb") as f: (priv, pub) = rsa.create_signing_keypair_from_string(f.read()) writekey, encprivkey, fingerprint = derive_mutable_keys((pub, priv)) -readkey = ssk_readkey_hash(writekey) -datakey = ssk_readkey_data_hash(iv, readkey) -storage_index = ssk_storage_index_hash(readkey) +readkey = hashutil.ssk_readkey_hash(writekey) +datakey = hashutil.ssk_readkey_data_hash(iv, readkey) +storage_index = hashutil.ssk_storage_index_hash(readkey) +write_enabler_master = hashutil.ssk_write_enabler_master_hash(writekey) +write_enabler = hashutil.ssk_write_enabler_hash(writekey, peerid) print("SDMF") print("writekey: ", base32.b2a(writekey)) print("readkey: ", base32.b2a(readkey)) -print("datakey: ", base32.b2a(datakey)) +print("datakey (iv = \x42 * 16): ", base32.b2a(datakey)) print("storage index: ", base32.b2a(storage_index)) print("encrypted private key: ", base32.b2a(encprivkey)) print("signature key hash: ", base32.b2a(fingerprint)) +print("write enabler master: ", base32.b2a(write_enabler_master)) +print("write enabler (peerid = \x42 * 20): ", base32.b2a(write_enabler)) (priv, pub) = rsa.create_signing_keypair(2048) priv_bytes = rsa.der_string_from_signing_key(priv)