Fix padding
This commit is contained in:
parent
55f1382401
commit
2518872872
@ -1,3 +1,7 @@
|
|||||||
|
# 0.3.0.0
|
||||||
|
- Better exception type (does no longer leak private information)
|
||||||
|
- 'Data.CryptoID.Poly' now supports padding the plaintext to a certain length before encryption
|
||||||
|
|
||||||
# 0.2.0.0
|
# 0.2.0.0
|
||||||
- Rename 'Data.CryptoID.Poly' to 'Data.CryptoID.ByteString'
|
- Rename 'Data.CryptoID.Poly' to 'Data.CryptoID.ByteString'
|
||||||
- Introduce 'Data.CryptoID.Poly' doing actual serialization
|
- Introduce 'Data.CryptoID.Poly' doing actual serialization
|
||||||
@ -12,3 +16,4 @@
|
|||||||
# 0.0.0
|
# 0.0.0
|
||||||
|
|
||||||
First published version
|
First published version
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
name: cryptoids
|
name: cryptoids
|
||||||
version: 0.2.0.0
|
version: 0.3.0.0
|
||||||
synopsis: Reversable and secure encoding of object ids as a bytestring
|
synopsis: Reversable and secure encoding of object ids as a bytestring
|
||||||
license: BSD3
|
license: BSD3
|
||||||
license-file: LICENSE
|
license-file: LICENSE
|
||||||
|
|||||||
@ -29,6 +29,7 @@ import Data.Binary.Put
|
|||||||
import Data.Binary.Get
|
import Data.Binary.Get
|
||||||
|
|
||||||
import Data.ByteString (ByteString)
|
import Data.ByteString (ByteString)
|
||||||
|
import qualified Data.ByteString as ByteString
|
||||||
import qualified Data.ByteString.Char8 as ByteString.Char
|
import qualified Data.ByteString.Char8 as ByteString.Char
|
||||||
|
|
||||||
import qualified Data.ByteString.Lazy as Lazy (ByteString)
|
import qualified Data.ByteString.Lazy as Lazy (ByteString)
|
||||||
@ -100,10 +101,19 @@ instance Binary CryptoIDKey where
|
|||||||
|
|
||||||
|
|
||||||
-- | Error cases that can be encountered during 'encrypt' and 'decrypt'
|
-- | Error cases that can be encountered during 'encrypt' and 'decrypt'
|
||||||
|
--
|
||||||
|
-- Care has been taken to ensure that presenting values of 'CryptoIDError' to an
|
||||||
|
-- attacker leaks no plaintext (it does leak information about the length of the
|
||||||
|
-- plaintext).
|
||||||
data CryptoIDError
|
data CryptoIDError
|
||||||
= AlgorithmError CryptoError
|
= AlgorithmError CryptoError
|
||||||
-- ^ One of the underlying cryptographic algorithms
|
-- ^ One of the underlying cryptographic algorithms
|
||||||
-- ('CryptoHash' or 'CryptoCipher') failed.
|
-- ('CryptoHash' or 'CryptoCipher') failed.
|
||||||
|
| PlaintextIsWrongLength Int
|
||||||
|
-- ^ The length of the plaintext is not a multiple of the block size of
|
||||||
|
-- 'CryptoCipher'
|
||||||
|
--
|
||||||
|
-- The length of the offending plaintext is included.
|
||||||
| NamespaceHashIsWrongLength ByteString
|
| NamespaceHashIsWrongLength ByteString
|
||||||
-- ^ The length of the digest produced by 'CryptoHash' does
|
-- ^ The length of the digest produced by 'CryptoHash' does
|
||||||
-- not match the block size of 'CryptoCipher'.
|
-- not match the block size of 'CryptoCipher'.
|
||||||
@ -112,10 +122,12 @@ data CryptoIDError
|
|||||||
--
|
--
|
||||||
-- This error should not occur and is included primarily
|
-- This error should not occur and is included primarily
|
||||||
-- for sake of totality.
|
-- for sake of totality.
|
||||||
| CiphertextConversionFailed
|
| CiphertextConversionFailed ByteString
|
||||||
-- ^ The produced 'ByteString' is the wrong length for conversion into a
|
-- ^ The produced 'ByteString' is the wrong length for deserialization into
|
||||||
-- ciphertext.
|
-- a ciphertext.
|
||||||
| DeserializationError (Lazy.ByteString, ByteOffset, String)
|
--
|
||||||
|
-- The offending 'ByteString' is included.
|
||||||
|
| DeserializationError
|
||||||
-- ^ The plaintext obtained by decrypting a ciphertext with the given
|
-- ^ The plaintext obtained by decrypting a ciphertext with the given
|
||||||
-- 'CryptoIDKey' in the context of the @namespace@ could not be
|
-- 'CryptoIDKey' in the context of the @namespace@ could not be
|
||||||
-- deserialized into a value of the expected @payload@-type.
|
-- deserialized into a value of the expected @payload@-type.
|
||||||
@ -183,8 +195,8 @@ encrypt :: forall m namespace.
|
|||||||
encrypt (keyMaterial -> key) plaintext = do
|
encrypt (keyMaterial -> key) plaintext = do
|
||||||
cipher <- cryptoFailable (cipherInit key :: CryptoFailable CryptoCipher)
|
cipher <- cryptoFailable (cipherInit key :: CryptoFailable CryptoCipher)
|
||||||
namespace <- namespace' (Proxy :: Proxy namespace)
|
namespace <- namespace' (Proxy :: Proxy namespace)
|
||||||
when (ByteArray.length plaintext `mod` blockSize cipher /= 0) $
|
when (ByteString.length plaintext `mod` blockSize cipher /= 0) $
|
||||||
throwM CiphertextConversionFailed
|
throwM . PlaintextIsWrongLength $ ByteString.length plaintext
|
||||||
return . CryptoID $ cbcEncrypt cipher namespace plaintext
|
return . CryptoID $ cbcEncrypt cipher namespace plaintext
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -33,11 +33,15 @@ import qualified Data.CryptoID.ByteString as ByteString (encrypt, decrypt)
|
|||||||
|
|
||||||
import Data.Binary
|
import Data.Binary
|
||||||
|
|
||||||
|
import Data.Monoid
|
||||||
|
|
||||||
import Data.ByteString (ByteString)
|
import Data.ByteString (ByteString)
|
||||||
|
import qualified Data.ByteString as ByteString
|
||||||
import qualified Data.ByteString.Lazy as Lazy.ByteString
|
import qualified Data.ByteString.Lazy as Lazy.ByteString
|
||||||
|
|
||||||
import GHC.TypeLits
|
import GHC.TypeLits
|
||||||
|
|
||||||
|
import Control.Monad
|
||||||
import Control.Monad.Catch (MonadThrow(..))
|
import Control.Monad.Catch (MonadThrow(..))
|
||||||
|
|
||||||
|
|
||||||
@ -50,10 +54,22 @@ encrypt :: forall a m c namespace.
|
|||||||
( KnownSymbol namespace
|
( KnownSymbol namespace
|
||||||
, MonadThrow m
|
, MonadThrow m
|
||||||
, Binary a
|
, Binary a
|
||||||
) => (ByteString -> m c) -> CryptoIDKey -> a -> m (CryptoID namespace c)
|
) => Maybe Int -- ^ Ensure the resulting ciphertext is of this size (needs to be a multiple of the block size of 'CryptoCipher' in bytes, otherwise an exception will be thrown at runtime)
|
||||||
encrypt encode' key plaintext = do
|
-> (ByteString -> m c)
|
||||||
cID <- ByteString.encrypt key . Lazy.ByteString.toStrict $ encode plaintext
|
-> CryptoIDKey
|
||||||
|
-> a
|
||||||
|
-> m (CryptoID namespace c)
|
||||||
|
encrypt pLength encode' key plaintext = do
|
||||||
|
cID <- ByteString.encrypt key <=< pad . Lazy.ByteString.toStrict $ encode plaintext
|
||||||
_ciphertext encode' cID
|
_ciphertext encode' cID
|
||||||
|
where
|
||||||
|
pad str
|
||||||
|
| Just l <- pLength
|
||||||
|
, l' <= l = return $ str <> ByteString.replicate (l - l') 0
|
||||||
|
| Just _ <- pLength = throwM $ CiphertextConversionFailed str
|
||||||
|
| otherwise = return str
|
||||||
|
where
|
||||||
|
l' = ByteString.length str
|
||||||
|
|
||||||
|
|
||||||
-- | Decrypt a serialized value
|
-- | Decrypt a serialized value
|
||||||
@ -67,7 +83,7 @@ decrypt decode key cID = do
|
|||||||
plaintext <- Lazy.ByteString.fromStrict <$> ByteString.decrypt key cID'
|
plaintext <- Lazy.ByteString.fromStrict <$> ByteString.decrypt key cID'
|
||||||
|
|
||||||
case decodeOrFail plaintext of
|
case decodeOrFail plaintext of
|
||||||
Left err -> throwM $ DeserializationError err
|
Left _ -> throwM DeserializationError
|
||||||
Right (rem, _, res)
|
Right (rem, _, res)
|
||||||
| Lazy.ByteString.all (== 0) rem -> return res
|
| Lazy.ByteString.all (== 0) rem -> return res
|
||||||
| otherwise -> throwM InvalidNamespaceDetected
|
| otherwise -> throwM InvalidNamespaceDetected
|
||||||
|
|||||||
@ -1,3 +1,6 @@
|
|||||||
|
# 1.2.0.0
|
||||||
|
- Pad plaintext before encryption, allowing encryption of payloads shorter than 128 bits
|
||||||
|
|
||||||
# 1.1.1.0
|
# 1.1.1.0
|
||||||
- Switch to using the new 'Data.CryptoID.Poly'
|
- Switch to using the new 'Data.CryptoID.Poly'
|
||||||
|
|
||||||
|
|||||||
@ -53,7 +53,7 @@ encrypt :: forall a m namespace.
|
|||||||
, Binary a
|
, Binary a
|
||||||
, MonadThrow m
|
, MonadThrow m
|
||||||
) => CryptoIDKey -> a -> m (CryptoUUID namespace)
|
) => CryptoIDKey -> a -> m (CryptoUUID namespace)
|
||||||
encrypt = Poly.encrypt $ maybe (throwM CiphertextConversionFailed) return . fromByteString . Lazy.ByteString.fromStrict
|
encrypt = Poly.encrypt (Just 16) $ \str -> maybe (throwM $ CiphertextConversionFailed str) return . fromByteString $ Lazy.ByteString.fromStrict str
|
||||||
|
|
||||||
|
|
||||||
-- | Decrypt an arbitrary serializable value
|
-- | Decrypt an arbitrary serializable value
|
||||||
@ -68,7 +68,7 @@ decrypt :: forall a m namespace.
|
|||||||
) => CryptoIDKey -> CryptoUUID namespace -> m a
|
) => CryptoIDKey -> CryptoUUID namespace -> m a
|
||||||
decrypt = Poly.decrypt $ check . decodeOrFail . toByteString
|
decrypt = Poly.decrypt $ check . decodeOrFail . toByteString
|
||||||
where
|
where
|
||||||
check (Left err) = throwM $ DeserializationError err
|
check (Left _) = throwM DeserializationError
|
||||||
check (Right (rem, _, res))
|
check (Right (rem, _, res))
|
||||||
| Lazy.ByteString.all (== 0) rem = return res
|
| Lazy.ByteString.all (== 0) rem = return res
|
||||||
| otherwise = throwM InvalidNamespaceDetected
|
| otherwise = throwM InvalidNamespaceDetected
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
name: uuid-crypto
|
name: uuid-crypto
|
||||||
version: 1.1.1.0
|
version: 1.2.0.0
|
||||||
synopsis: Reversable and secure encoding of object ids as uuids
|
synopsis: Reversable and secure encoding of object ids as uuids
|
||||||
license: BSD3
|
license: BSD3
|
||||||
license-file: LICENSE
|
license-file: LICENSE
|
||||||
@ -28,7 +28,7 @@ library
|
|||||||
other-extensions: ScopedTypeVariables
|
other-extensions: ScopedTypeVariables
|
||||||
build-depends: base >=4.9 && <4.11
|
build-depends: base >=4.9 && <4.11
|
||||||
, cryptoids-types ==0.0.0
|
, cryptoids-types ==0.0.0
|
||||||
, cryptoids ==0.2.0.*
|
, cryptoids ==0.3.0.*
|
||||||
, uuid >=1.3.13 && <1.4
|
, uuid >=1.3.13 && <1.4
|
||||||
, binary >=0.8.3.0 && <0.9
|
, binary >=0.8.3.0 && <0.9
|
||||||
, bytestring >=0.10.8.1 && <0.11
|
, bytestring >=0.10.8.1 && <0.11
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user