packages feed

hpke 0.1.0 → 0.2.0

raw patch · 7 files changed

+72/−20 lines, 7 filesdep ~cryptonPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: crypton

API changes (from Hackage documentation)

+ Crypto.HPKE: ExportError :: String -> HPKEError
- Crypto.HPKE: exportR :: ContextR -> Info -> Int -> Key
+ Crypto.HPKE: exportR :: ContextR -> Info -> Int -> Either HPKEError Key
- Crypto.HPKE: exportS :: ContextS -> Info -> Int -> Key
+ Crypto.HPKE: exportS :: ContextS -> Info -> Int -> Either HPKEError Key
- Crypto.HPKE.Internal: labeledExpand :: KDF h => Suite -> PRK h -> Label -> Info -> Int -> Key
+ Crypto.HPKE.Internal: labeledExpand :: KDF h => Suite -> PRK h -> Label -> Info -> Int -> Either HPKEError Key

Files

ChangeLog.md view
@@ -1,5 +1,18 @@ # ChangeLog for hpke +## 0.2.0++* Breaking change: `exportS` and `exportR` return `Either HPKEError Key`+  rather than `Key`.  RFC 9180 section 5.3 allows an export of at most+  `255 * Nh` octets and the length is the caller's to choose, so the refusal+  now has somewhere to go.  Nothing was total here before -- a length beyond+  65535 did not fit the two octets `LabeledExpand` writes it into, and+  crypton raised -- and from crypton 2.0.0 the shorter limit raises as well.+* Breaking change: `HPKEError` gains `ExportError`, which is what the above+  reports.  It is appended, so the existing constructors are where they+  were, but an exhaustive `case` without a wildcard will warn.+* Supporting crypton 2.0.+ ## 0.1.0  * Using "ram" instead of "memory".
Crypto/HPKE/Context.hs view
@@ -28,7 +28,7 @@     { seqRefS :: IORef Integer     , sealS :: Seal     , nonceBaseS :: Nonce-    , expandS :: Info -> Int -> Key+    , expandS :: Info -> Int -> Either HPKEError Key     }  -- | Context for receivers.@@ -36,7 +36,7 @@     { seqRefR :: IORef Integer     , openR :: Open     , nonceBaseR :: Nonce-    , expandR :: Info -> Int -> Key+    , expandR :: Info -> Int -> Either HPKEError Key     }  ----------------------------------------------------------------@@ -76,12 +76,18 @@ ----------------------------------------------------------------  -- | Exporting secret.-exportS :: ContextS -> Info -> Int -> Key+--+-- RFC 9180 section 5.3 allows a length of at most @255 * Nh@, where @Nh@ is+-- the output of the KDF's hash; a longer one is 'Left' 'ExportError'.+exportS :: ContextS -> Info -> Int -> Either HPKEError Key exportS ContextS{..} exporter_context len =     expandS exporter_context len  -- | Exporting secret.-exportR :: ContextR -> Info -> Int -> Key+--+-- RFC 9180 section 5.3 allows a length of at most @255 * Nh@, where @Nh@ is+-- the output of the KDF's hash; a longer one is 'Left' 'ExportError'.+exportR :: ContextR -> Info -> Int -> Either HPKEError Key exportR ContextR{..} exporter_context len =     expandR exporter_context len @@ -91,7 +97,7 @@     :: Key     -> Nonce     -> (Key -> Seal)-    -> (Info -> Int -> Key)+    -> (Info -> Int -> Either HPKEError Key)     -> IO ContextS newContextS key nonce_base seal' expand = do     seqref <- newIORef 0@@ -109,7 +115,7 @@     :: Key     -> Nonce     -> (Key -> Open)-    -> (Info -> Int -> Key)+    -> (Info -> Int -> Either HPKEError Key)     -> IO ContextR newContextR key nonce_base open' expand = do     seqref <- newIORef 0
Crypto/HPKE/KDF.hs view
@@ -12,6 +12,7 @@ ) where +import Crypto.Hash.IO (hashDigestSize) import Crypto.Hash.Algorithms (     HashAlgorithm,     SHA256 (..),@@ -27,8 +28,14 @@  class KDF h where     labeledExtract :: Suite -> Salt -> Label -> IKM -> PRK h-    labeledExpand :: Suite -> PRK h -> Label -> Info -> Int -> Key +    -- | RFC 9180 section 5.3 allows an output of at most @255 * Nh@ octets,+    -- which is also what HKDF's counter can reach.  A longer one is refused+    -- here rather than left to the HKDF underneath, whose way of saying so+    -- is an exception.+    labeledExpand+        :: Suite -> PRK h -> Label -> Info -> Int -> Either HPKEError Key+ instance KDF SHA256 where     labeledExtract = labeledExtract_     labeledExpand = labeledExpand_@@ -50,9 +57,20 @@     labeled_ikm = "HPKE-v1" <> suite <> label <> ikm  labeledExpand_-    :: HashAlgorithm a => Suite -> PRK a -> Label -> Info -> Int -> Key-labeledExpand_ suite prk label info len = HKDF.expand prk labeled_info len+    :: forall a+     . HashAlgorithm a+    => Suite -> PRK a -> Label -> Info -> Int -> Either HPKEError Key+labeledExpand_ suite prk label info len+    | len < 0 || len > maxLen =+        Left $+            ExportError $+                "length "+                    ++ show len+                    ++ " is outside 0 .. "+                    ++ show maxLen+    | otherwise = Right $ HKDF.expand prk labeled_info len   where+    maxLen = 255 * hashDigestSize (undefined :: a)     labeled_info =         i2ospOf_ 2 (fromIntegral len) <> "HPKE-v1" <> suite <> label <> info @@ -67,5 +85,7 @@     eae_prk :: PRK h     eae_prk = labeledExtract suite "" "eae_prk" $ convert dh     siz = hashDigestSize h+    -- the hash's own digest size, so the length is in range by construction     shared_secret =-        labeledExpand suite eae_prk "shared_secret" kem_context siz+        either (const "") id $+            labeledExpand suite eae_prk "shared_secret" kem_context siz
Crypto/HPKE/KeySchedule.hs view
@@ -47,7 +47,11 @@     -> PSK_ID     -> SharedSecret     -> Either HPKEError (Key, Nonce, Int, PRK h)-keySchedule h suite nk nn mode info psk psk_id shared_secret =+keySchedule h suite nk nn mode info psk psk_id shared_secret = do+    key <- labeledExpand suite secret "key" key_schedule_context nk+    base_nonce <- labeledExpand suite secret "base_nonce" key_schedule_context nn+    exporter_secret <-+        labeledExpand suite secret "exp" key_schedule_context $ hashDigestSize h     case toPRK exporter_secret of         Nothing -> Left $ KeyScheduleError "cannot convert to PRK"         Just prk -> Right (key, base_nonce, 0, prk)@@ -60,7 +64,4 @@      secret = labeledExtract suite (convert shared_secret) "secret" psk :: PRK h -    key = labeledExpand suite secret "key" key_schedule_context nk-    base_nonce = labeledExpand suite secret "base_nonce" key_schedule_context nn -    exporter_secret = labeledExpand suite secret "exp" key_schedule_context $ hashDigestSize h
Crypto/HPKE/Types.hs view
@@ -66,6 +66,9 @@     | DeriveKeyPairError String     | -- | Original       KeyScheduleError String+    | -- | Original.  An export longer than the @255 * Nh@ that RFC 9180+      -- section 5.3 allows.+      ExportError String     | Unsupported String     deriving (Eq, Show) 
hpke.cabal view
@@ -1,6 +1,6 @@ cabal-version:      >=1.10 name:               hpke-version:            0.1.0+version:            0.2.0 license:            BSD3 license-file:       LICENSE maintainer:         kazu@iij.ad.jp@@ -32,7 +32,7 @@         base >=4.7 && <5,         base16-bytestring,         bytestring,-        crypton >= 1.1.0 && <1.2,+        crypton >= 1.1.0 && <2.1,         ram      default-extensions: Strict StrictData
test/Test.hs view
@@ -65,10 +65,19 @@     pt1 <- open ctxR aad1 ct1     pt1 `shouldBe` pt -    exportS ctxS exporter_context0 32 `shouldBe` sec0-    exportR ctxR exporter_context0 32 `shouldBe` sec0-    exportS ctxS exporter_context1 32 `shouldBe` sec1-    exportS ctxS exporter_context2 32 `shouldBe` sec2+    exportS ctxS exporter_context0 32 `shouldBe` Right sec0+    exportR ctxR exporter_context0 32 `shouldBe` Right sec0+    exportS ctxS exporter_context1 32 `shouldBe` Right sec1+    exportS ctxS exporter_context2 32 `shouldBe` Right sec2++    -- RFC 9180 section 5.3 allows at most 255*Nh octets, which is 16320+    -- even for SHA-512, the widest hash here+    case exportS ctxS exporter_context0 20000 of+        Left (ExportError _) -> return ()+        r -> expectationFailure $ "an over-long export was not refused: " ++ show (fmap (const ()) r)+    case exportR ctxR exporter_context0 20000 of+        Left (ExportError _) -> return ()+        r -> expectationFailure $ "an over-long export was not refused: " ++ show (fmap (const ()) r)   where     info = B16.decodeLenient _info     pkEm = EncodedPublicKey $ B16.decodeLenient _pkEm