tahoe-chk-0.2.0.0: src/Tahoe/CHK/Crypto.hs
{-# LANGUAGE TypeApplications #-}
module Tahoe.CHK.Crypto (
sha1,
sha256,
sha256d,
storageIndexLength,
toBytes,
taggedHash,
taggedHash',
taggedPairHash,
taggedPairHash',
blockHash,
blockHash',
storageIndexHash,
ciphertextTag,
ciphertextSegmentHash,
ciphertextSegmentHash',
uriExtensionHash,
convergenceEncryptionTag,
convergenceEncryptionHashLazy,
convergenceSecretLength,
) where
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as BL
import Crypto.Hash (
Digest,
HashAlgorithm,
hash,
hashDigestSize,
hashlazy,
)
import Data.ByteArray (convert)
import Crypto.Cipher.AES (AES128)
import Crypto.Hash.Algorithms (
SHA1,
SHA256 (SHA256),
)
import Tahoe.CHK.Cipher (Key)
import Tahoe.CHK.SHA256d (Digest' (..), SHA256d, toBytes)
import Tahoe.CHK.Types (Parameters (Parameters), StorageIndex)
import Tahoe.CHK.URIExtension (
URIExtension,
showBytes,
uriExtensionToBytes,
)
import Tahoe.Netstring (
netstring,
)
sha1 :: B.ByteString -> B.ByteString
sha1 xs = toBytes (hash xs :: Digest SHA1)
sha256 :: B.ByteString -> B.ByteString
sha256 xs = toBytes (hash xs :: Digest SHA256)
sha256d :: B.ByteString -> B.ByteString
sha256d = toBytes . (hash :: B.ByteString -> Digest SHA256d)
taggedHash :: Int -> B.ByteString -> B.ByteString -> B.ByteString
taggedHash size tag bytes = B.take size . toBytes $ taggedHash' @SHA256d tag bytes
{- | Compute the "tagged hash" of a byte string: the hash of the concatenation
of the netstring encoding of a tag and the given bytes.
-}
taggedHash' :: HashAlgorithm hash => B.ByteString -> B.ByteString -> Digest' hash
taggedHash' tag bytes = Digest' . hash . B.concat $ [netstring tag, bytes]
taggedPairHash :: Int -> B.ByteString -> B.ByteString -> B.ByteString -> B.ByteString
taggedPairHash size tag left right = B.take size . toBytes $ taggedPairHash' @SHA256d tag left right
{- | Compute the "tagged pair hash" of two byte strings: the hash of the
concatenation of the netstring encoding of a tag and each of two other byte
strings.
-}
taggedPairHash' :: HashAlgorithm hash => B.ByteString -> B.ByteString -> B.ByteString -> Digest' hash
taggedPairHash' tag left right = Digest' . hash . B.concat $ [netstring tag, netstring left, netstring right]
blockTag :: B.ByteString
blockTag = "allmydata_encoded_subshare_v1"
-- allmydata.util.hashutil.block_hash
blockHash :: B.ByteString -> B.ByteString
blockHash = taggedHash (hashDigestSize SHA256) blockTag
{- | Compute the hash of a share block. This is the same function as
allmydata.util.hashutil.block_hash.
-}
blockHash' :: HashAlgorithm hash => B.ByteString -> Digest' hash
blockHash' = taggedHash' blockTag
storageIndexTag :: B.ByteString
storageIndexTag = "allmydata_immutable_key_to_storage_index_v1"
-- Compute the storage index for a given encryption key
-- allmydata.util.hashutil.storage_index_hash
storageIndexHash :: Key AES128 -> StorageIndex
storageIndexHash = taggedHash storageIndexLength storageIndexTag . convert
ciphertextTag :: B.ByteString
ciphertextTag = "allmydata_crypttext_v1"
ciphertextSegmentTag :: B.ByteString
ciphertextSegmentTag = "allmydata_crypttext_segment_v1"
ciphertextSegmentHash :: B.ByteString -> B.ByteString
ciphertextSegmentHash = toBytes . ciphertextSegmentHash' @SHA256d
-- | Compute the hash of a segment of ciphertext.
ciphertextSegmentHash' :: HashAlgorithm hash => B.ByteString -> Digest' hash
ciphertextSegmentHash' = taggedHash' ciphertextSegmentTag
uriExtensionTag :: B.ByteString
uriExtensionTag = "allmydata_uri_extension_v1"
uriExtensionHash :: URIExtension -> B.ByteString
uriExtensionHash = taggedHash (hashDigestSize SHA256) uriExtensionTag . uriExtensionToBytes
convergenceEncryptionTagPrefix :: B.ByteString
convergenceEncryptionTagPrefix = "allmydata_immutable_content_to_key_with_added_secret_v1+"
convergenceEncryptionTag :: B.ByteString -> Parameters -> B.ByteString
convergenceEncryptionTag secret (Parameters segmentSize total _ required) =
tag
where
tag = B.concat [convergenceEncryptionTagPrefix, netstring secret, netstring paramTag]
paramTag = B.intercalate "," . map showBytes $ [requiredI, totalI, segmentSizeI]
requiredI = toInteger required
totalI = toInteger total
segmentSizeI = toInteger segmentSize
-- Compute the strict convergence encryption hash on a lazy data parameter.
convergenceEncryptionHashLazy :: B.ByteString -> Parameters -> BL.ByteString -> B.ByteString
convergenceEncryptionHashLazy secret params bytes =
-- It was somewhat helpful during development/debugging to make this
-- function return this instead:
--
-- BL.toStrict toHash
--
B.take convergenceSecretLength theSHA256d
where
theSHA256d = toBytes (hashlazy toHash :: Digest SHA256d)
toHash :: BL.ByteString
toHash = BL.concat [tag, bytes]
tag = BL.fromStrict . netstring $ convergenceEncryptionTag secret params
type ByteLength = Int
convergenceSecretLength :: ByteLength
convergenceSecretLength = 16
storageIndexLength :: ByteLength
storageIndexLength = 16