{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}
module Crypto.Nettle.CCM
( ccmInit
, ccmInitTLS
) where
import Crypto.Cipher.Types
import qualified Data.ByteString as B
import Data.Byteable
import Nettle.Utils
{-# ANN module "HLint: ignore Use camelCase" #-}
data CCM cipher
= (Int, Int, B.ByteString) B.ByteString
| CCM_Enc (Int, Int, B.ByteString) B.ByteString (IV cipher) B.ByteString
| CCM_Dec (Int, Int, B.ByteString) B.ByteString (IV cipher) B.ByteString
ccmInit
:: (BlockCipher cipher, Byteable iv)
=> Int
-> Int
-> cipher
-> iv
-> Maybe (AEAD cipher)
ccmInit :: forall cipher iv.
(BlockCipher cipher, Byteable iv) =>
Int -> Int -> cipher -> iv -> Maybe (AEAD cipher)
ccmInit Int
t Int
q cipher
cipher iv
nonce = Int -> Int -> cipher -> iv -> Maybe (CCM cipher)
forall cipher iv.
(BlockCipher cipher, Byteable iv) =>
Int -> Int -> cipher -> iv -> Maybe (CCM cipher)
ccm_init Int
t Int
q cipher
cipher iv
nonce Maybe (CCM cipher)
-> (CCM cipher -> Maybe (AEAD cipher)) -> Maybe (AEAD cipher)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= AEAD cipher -> Maybe (AEAD cipher)
forall a. a -> Maybe a
Just (AEAD cipher -> Maybe (AEAD cipher))
-> (CCM cipher -> AEAD cipher) -> CCM cipher -> Maybe (AEAD cipher)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. cipher -> AEADState cipher -> AEAD cipher
forall cipher. cipher -> AEADState cipher -> AEAD cipher
AEAD cipher
cipher (AEADState cipher -> AEAD cipher)
-> (CCM cipher -> AEADState cipher) -> CCM cipher -> AEAD cipher
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CCM cipher -> AEADState cipher
forall cipher st. AEADModeImpl cipher st => st -> AEADState cipher
AEADState
ccm_init :: (BlockCipher cipher, Byteable iv) => Int -> Int -> cipher -> iv -> Maybe (CCM cipher)
ccm_init :: forall cipher iv.
(BlockCipher cipher, Byteable iv) =>
Int -> Int -> cipher -> iv -> Maybe (CCM cipher)
ccm_init Int
t Int
q cipher
cipher iv
nonce = if Bool
valid then CCM cipher -> Maybe (CCM cipher)
forall a. a -> Maybe a
Just (CCM cipher -> Maybe (CCM cipher))
-> CCM cipher -> Maybe (CCM cipher)
forall a b. (a -> b) -> a -> b
$ (Int, Int, ByteString) -> ByteString -> CCM cipher
forall cipher. (Int, Int, ByteString) -> ByteString -> CCM cipher
CCM_Header (Int
t, Int
q, iv -> ByteString
forall a. Byteable a => a -> ByteString
toBytes iv
nonce) ByteString
B.empty else Maybe (CCM cipher)
forall a. Maybe a
Nothing
where
valid :: Bool
valid = Bool
valid_cipher Bool -> Bool -> Bool
&& Bool
valid_t Bool -> Bool -> Bool
&& Bool
valid_q Bool -> Bool -> Bool
&& Bool
valid_nonce
valid_cipher :: Bool
valid_cipher = cipher -> Int
forall cipher. BlockCipher cipher => cipher -> Int
blockSize cipher
cipher Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
16
valid_t :: Bool
valid_t = Int
t Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
4 Bool -> Bool -> Bool
&& Int
t Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
16 Bool -> Bool -> Bool
&& Int -> Bool
forall a. Integral a => a -> Bool
even Int
t
valid_q :: Bool
valid_q = Int
q Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
2 Bool -> Bool -> Bool
&& Int
q Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
8
nonce_len :: Int
nonce_len = Int
15 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
q
valid_nonce :: Bool
valid_nonce = iv -> Int
forall a. Byteable a => a -> Int
byteableLength iv
nonce Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
nonce_len
ccmInitTLS
:: (BlockCipher cipher, Byteable iv)
=> cipher
-> iv
-> Maybe (AEAD cipher)
ccmInitTLS :: forall cipher iv.
(BlockCipher cipher, Byteable iv) =>
cipher -> iv -> Maybe (AEAD cipher)
ccmInitTLS = Int -> Int -> cipher -> iv -> Maybe (AEAD cipher)
forall cipher iv.
(BlockCipher cipher, Byteable iv) =>
Int -> Int -> cipher -> iv -> Maybe (AEAD cipher)
ccmInit Int
16 Int
3
ccm_encodeAdditionalLength :: B.ByteString -> B.ByteString
ccm_encodeAdditionalLength :: ByteString -> ByteString
ccm_encodeAdditionalLength ByteString
s = ByteString -> ByteString -> ByteString
B.append (Int -> ByteString
forall {n}. Integral n => n -> ByteString
encLen (Int -> ByteString) -> Int -> ByteString
forall a b. (a -> b) -> a -> b
$ ByteString -> Int
B.length ByteString
s) ByteString
s where
encLen :: n -> ByteString
encLen n
n
| n
n n -> n -> Bool
forall a. Eq a => a -> a -> Bool
== n
0 = ByteString
B.empty
| n
n n -> n -> Bool
forall a. Ord a => a -> a -> Bool
< (n
2n -> Int -> n
forall a b. (Num a, Integral b) => a -> b -> a
^(Int
16::Int)n -> n -> n
forall a. Num a => a -> a -> a
-n
2n -> Int -> n
forall a b. (Num a, Integral b) => a -> b -> a
^(Int
8::Int)) = [Word8] -> ByteString
B.pack ([Word8] -> ByteString) -> [Word8] -> ByteString
forall a b. (a -> b) -> a -> b
$ Int -> n -> [Word8]
forall n. Integral n => Int -> n -> [Word8]
netEncode Int
2 n
n
| n
n n -> n -> Bool
forall a. Ord a => a -> a -> Bool
< (n
2n -> Int -> n
forall a b. (Num a, Integral b) => a -> b -> a
^(Int
32::Int)) = [Word8] -> ByteString
B.pack (Word8
0xffWord8 -> [Word8] -> [Word8]
forall a. a -> [a] -> [a]
:Word8
0xfeWord8 -> [Word8] -> [Word8]
forall a. a -> [a] -> [a]
:Int -> n -> [Word8]
forall n. Integral n => Int -> n -> [Word8]
netEncode Int
4 n
n)
| Bool
otherwise = [Word8] -> ByteString
B.pack (Word8
0xffWord8 -> [Word8] -> [Word8]
forall a. a -> [a] -> [a]
:Word8
0xffWord8 -> [Word8] -> [Word8]
forall a. a -> [a] -> [a]
:Int -> n -> [Word8]
forall n. Integral n => Int -> n -> [Word8]
netEncode Int
8 n
n)
pad_zero :: Int -> B.ByteString -> B.ByteString
pad_zero :: Int -> ByteString -> ByteString
pad_zero Int
l ByteString
s = ByteString -> ByteString -> ByteString
B.append ByteString
s (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ Int -> Word8 -> ByteString
B.replicate (Int
l Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1 Int -> Int -> Int
forall a. Num a => a -> a -> a
- (ByteString -> Int
B.length ByteString
s Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
l) Word8
0
_makeIV :: BlockCipher cipher => B.ByteString -> IV cipher
_makeIV :: forall cipher. BlockCipher cipher => ByteString -> IV cipher
_makeIV ByteString
iv = let Just IV cipher
iv' = ByteString -> Maybe (IV cipher)
forall b c. (Byteable b, BlockCipher c) => b -> Maybe (IV c)
makeIV ByteString
iv in IV cipher
iv'
ccm_start_iv :: BlockCipher cipher => (Int, Int, B.ByteString) -> IV cipher
ccm_start_iv :: forall cipher.
BlockCipher cipher =>
(Int, Int, ByteString) -> IV cipher
ccm_start_iv (Int
_, Int
q, ByteString
nonce) = ByteString -> IV cipher
forall cipher. BlockCipher cipher => ByteString -> IV cipher
_makeIV (ByteString -> IV cipher) -> ByteString -> IV cipher
forall a b. (a -> b) -> a -> b
$ [ByteString] -> ByteString
B.concat [Word8 -> ByteString
B.singleton (Word8 -> ByteString) -> Word8 -> ByteString
forall a b. (a -> b) -> a -> b
$ Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Word8) -> Int -> Word8
forall a b. (a -> b) -> a -> b
$ Int
q Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1, ByteString
nonce, Int -> Word8 -> ByteString
B.replicate (Int
q Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Word8
0, Word8 -> ByteString
B.singleton Word8
1]
ccm_tag_iv :: BlockCipher cipher => (Int, Int, B.ByteString) -> IV cipher
ccm_tag_iv :: forall cipher.
BlockCipher cipher =>
(Int, Int, ByteString) -> IV cipher
ccm_tag_iv (Int
_, Int
q, ByteString
nonce) = ByteString -> IV cipher
forall cipher. BlockCipher cipher => ByteString -> IV cipher
_makeIV (ByteString -> IV cipher) -> ByteString -> IV cipher
forall a b. (a -> b) -> a -> b
$ [ByteString] -> ByteString
B.concat [Word8 -> ByteString
B.singleton (Word8 -> ByteString) -> Word8 -> ByteString
forall a b. (a -> b) -> a -> b
$ Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Word8) -> Int -> Word8
forall a b. (a -> b) -> a -> b
$ Int
q Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1, ByteString
nonce, Int -> Word8 -> ByteString
B.replicate Int
q Word8
0]
ccm_crypt :: BlockCipher cipher => cipher -> IV cipher -> B.ByteString -> (B.ByteString, IV cipher)
ccm_crypt :: forall cipher.
BlockCipher cipher =>
cipher -> IV cipher -> ByteString -> (ByteString, IV cipher)
ccm_crypt cipher
key IV cipher
iv ByteString
src = let
blocks :: Int
blocks = (ByteString -> Int
B.length ByteString
src Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
15) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
16
dst :: ByteString
dst = cipher -> IV cipher -> ByteString -> ByteString
forall cipher.
BlockCipher cipher =>
cipher -> IV cipher -> ByteString -> ByteString
ctrCombine cipher
key IV cipher
iv ByteString
src
iv' :: IV cipher
iv' = IV cipher -> Int -> IV cipher
forall c. BlockCipher c => IV c -> Int -> IV c
ivAdd IV cipher
iv Int
blocks
in (ByteString
dst, IV cipher
iv')
ccm_tag :: BlockCipher cipher => cipher -> (Int, Int, B.ByteString) -> B.ByteString -> B.ByteString -> Int -> AuthTag
ccm_tag :: forall cipher.
BlockCipher cipher =>
cipher
-> (Int, Int, ByteString)
-> ByteString
-> ByteString
-> Int
-> AuthTag
ccm_tag cipher
key (Int
t, Int
q, ByteString
nonce) ByteString
header ByteString
msg Int
taglen = let
auth_flags :: Word8
auth_flags = (if ByteString -> Int
B.length ByteString
header Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0 then Word8
64 else Word8
0) Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
+ Word8
4Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
*(Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
t Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
2) Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
+ (Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
q Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
1)
b0 :: ByteString
b0 = [ByteString] -> ByteString
B.concat [Word8 -> ByteString
B.singleton Word8
auth_flags, ByteString
nonce, [Word8] -> ByteString
B.pack ([Word8] -> ByteString) -> [Word8] -> ByteString
forall a b. (a -> b) -> a -> b
$ Int -> Int -> [Word8]
forall n. Integral n => Int -> n -> [Word8]
netEncode Int
q (Int -> [Word8]) -> Int -> [Word8]
forall a b. (a -> b) -> a -> b
$ ByteString -> Int
B.length ByteString
msg]
blocks :: ByteString
blocks = [ByteString] -> ByteString
B.concat [ByteString
b0, Int -> ByteString -> ByteString
pad_zero Int
16 (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString
ccm_encodeAdditionalLength ByteString
header, Int -> ByteString -> ByteString
pad_zero Int
16 ByteString
msg]
tag :: ByteString
tag = (ByteString, IV cipher) -> ByteString
forall a b. (a, b) -> a
fst ((ByteString, IV cipher) -> ByteString)
-> (ByteString, IV cipher) -> ByteString
forall a b. (a -> b) -> a -> b
$ cipher -> IV cipher -> ByteString -> (ByteString, IV cipher)
forall cipher.
BlockCipher cipher =>
cipher -> IV cipher -> ByteString -> (ByteString, IV cipher)
ccm_crypt cipher
key ((Int, Int, ByteString) -> IV cipher
forall cipher.
BlockCipher cipher =>
(Int, Int, ByteString) -> IV cipher
ccm_tag_iv (Int
t, Int
q, ByteString
nonce)) (ByteString -> (ByteString, IV cipher))
-> ByteString -> (ByteString, IV cipher)
forall a b. (a -> b) -> a -> b
$ Int -> ByteString -> ByteString
B.drop (ByteString -> Int
B.length ByteString
blocks Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
16) (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ cipher -> IV cipher -> ByteString -> ByteString
forall cipher.
BlockCipher cipher =>
cipher -> IV cipher -> ByteString -> ByteString
cbcEncrypt cipher
key IV cipher
forall c. BlockCipher c => IV c
nullIV ByteString
blocks
in ByteString -> AuthTag
AuthTag (ByteString -> AuthTag) -> ByteString -> AuthTag
forall a b. (a -> b) -> a -> b
$ Int -> ByteString -> ByteString
B.take Int
taglen ByteString
tag
instance BlockCipher cipher => AEADModeImpl cipher (CCM cipher) where
aeadStateAppendHeader :: cipher -> CCM cipher -> ByteString -> CCM cipher
aeadStateAppendHeader cipher
_ (CCM_Header (Int
t, Int
q, ByteString
nonce) ByteString
header) ByteString
src = (Int, Int, ByteString) -> ByteString -> CCM cipher
forall cipher. (Int, Int, ByteString) -> ByteString -> CCM cipher
CCM_Header (Int
t, Int
q, ByteString
nonce) (ByteString -> CCM cipher) -> ByteString -> CCM cipher
forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString -> ByteString
B.append ByteString
header ByteString
src
aeadStateAppendHeader cipher
_ CCM cipher
_ ByteString
_ = [Char] -> CCM cipher
forall a. HasCallStack => [Char] -> a
error [Char]
"can't aeadStateAppendHeader anymore, already have real data"
aeadStateEncrypt :: cipher -> CCM cipher -> ByteString -> (ByteString, CCM cipher)
aeadStateEncrypt cipher
key (CCM_Header (Int
t, Int
q, ByteString
nonce) ByteString
header) ByteString
src = cipher -> CCM cipher -> ByteString -> (ByteString, CCM cipher)
forall cipher state.
AEADModeImpl cipher state =>
cipher -> state -> ByteString -> (ByteString, state)
aeadStateEncrypt cipher
key ((Int, Int, ByteString)
-> ByteString -> IV cipher -> ByteString -> CCM cipher
forall cipher.
(Int, Int, ByteString)
-> ByteString -> IV cipher -> ByteString -> CCM cipher
CCM_Enc (Int
t, Int
q, ByteString
nonce) ByteString
header IV cipher
iv ByteString
B.empty) ByteString
src
where iv :: IV cipher
iv = (Int, Int, ByteString) -> IV cipher
forall cipher.
BlockCipher cipher =>
(Int, Int, ByteString) -> IV cipher
ccm_start_iv (Int
t, Int
q, ByteString
nonce)
aeadStateEncrypt cipher
key (CCM_Enc (Int
t, Int
q, ByteString
nonce) ByteString
header IV cipher
iv ByteString
msg) ByteString
src = let
(ByteString
dst, IV cipher
iv') = cipher -> IV cipher -> ByteString -> (ByteString, IV cipher)
forall cipher.
BlockCipher cipher =>
cipher -> IV cipher -> ByteString -> (ByteString, IV cipher)
ccm_crypt cipher
key IV cipher
iv ByteString
src
in (ByteString
dst, (Int, Int, ByteString)
-> ByteString -> IV cipher -> ByteString -> CCM cipher
forall cipher.
(Int, Int, ByteString)
-> ByteString -> IV cipher -> ByteString -> CCM cipher
CCM_Enc (Int
t, Int
q, ByteString
nonce) ByteString
header IV cipher
iv' (ByteString -> CCM cipher) -> ByteString -> CCM cipher
forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString -> ByteString
B.append ByteString
msg ByteString
src)
aeadStateEncrypt cipher
_ CCM cipher
_ ByteString
_ = [Char] -> (ByteString, CCM cipher)
forall a. HasCallStack => [Char] -> a
error [Char]
"can't aeadStateEncrypt anymore, already is in decrypt mode"
aeadStateDecrypt :: cipher -> CCM cipher -> ByteString -> (ByteString, CCM cipher)
aeadStateDecrypt cipher
key (CCM_Header (Int
t, Int
q, ByteString
nonce) ByteString
header) ByteString
src = cipher -> CCM cipher -> ByteString -> (ByteString, CCM cipher)
forall cipher state.
AEADModeImpl cipher state =>
cipher -> state -> ByteString -> (ByteString, state)
aeadStateDecrypt cipher
key ((Int, Int, ByteString)
-> ByteString -> IV cipher -> ByteString -> CCM cipher
forall cipher.
(Int, Int, ByteString)
-> ByteString -> IV cipher -> ByteString -> CCM cipher
CCM_Dec (Int
t, Int
q, ByteString
nonce) ByteString
header IV cipher
iv ByteString
B.empty) ByteString
src
where iv :: IV cipher
iv = (Int, Int, ByteString) -> IV cipher
forall cipher.
BlockCipher cipher =>
(Int, Int, ByteString) -> IV cipher
ccm_start_iv (Int
t, Int
q, ByteString
nonce)
aeadStateDecrypt cipher
key (CCM_Dec (Int
t, Int
q, ByteString
nonce) ByteString
header IV cipher
iv ByteString
msg) ByteString
src = let
(ByteString
dst, IV cipher
iv') = cipher -> IV cipher -> ByteString -> (ByteString, IV cipher)
forall cipher.
BlockCipher cipher =>
cipher -> IV cipher -> ByteString -> (ByteString, IV cipher)
ccm_crypt cipher
key IV cipher
iv ByteString
src
in (ByteString
dst, (Int, Int, ByteString)
-> ByteString -> IV cipher -> ByteString -> CCM cipher
forall cipher.
(Int, Int, ByteString)
-> ByteString -> IV cipher -> ByteString -> CCM cipher
CCM_Enc (Int
t, Int
q, ByteString
nonce) ByteString
header IV cipher
iv' (ByteString -> CCM cipher) -> ByteString -> CCM cipher
forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString -> ByteString
B.append ByteString
msg ByteString
dst)
aeadStateDecrypt cipher
_ CCM cipher
_ ByteString
_ = [Char] -> (ByteString, CCM cipher)
forall a. HasCallStack => [Char] -> a
error [Char]
"can't aeadStateDecrypt anymore, already is in encrypt mode"
aeadStateFinalize :: cipher -> CCM cipher -> Int -> AuthTag
aeadStateFinalize cipher
key (CCM_Header (Int
t, Int
q, ByteString
nonce) ByteString
header ) Int
taglen = cipher
-> (Int, Int, ByteString)
-> ByteString
-> ByteString
-> Int
-> AuthTag
forall cipher.
BlockCipher cipher =>
cipher
-> (Int, Int, ByteString)
-> ByteString
-> ByteString
-> Int
-> AuthTag
ccm_tag cipher
key (Int
t, Int
q, ByteString
nonce) ByteString
header ByteString
B.empty Int
taglen
aeadStateFinalize cipher
key (CCM_Enc (Int
t, Int
q, ByteString
nonce) ByteString
header IV cipher
_ ByteString
msg) Int
taglen = cipher
-> (Int, Int, ByteString)
-> ByteString
-> ByteString
-> Int
-> AuthTag
forall cipher.
BlockCipher cipher =>
cipher
-> (Int, Int, ByteString)
-> ByteString
-> ByteString
-> Int
-> AuthTag
ccm_tag cipher
key (Int
t, Int
q, ByteString
nonce) ByteString
header ByteString
msg Int
taglen
aeadStateFinalize cipher
key (CCM_Dec (Int
t, Int
q, ByteString
nonce) ByteString
header IV cipher
_ ByteString
msg) Int
taglen = cipher
-> (Int, Int, ByteString)
-> ByteString
-> ByteString
-> Int
-> AuthTag
forall cipher.
BlockCipher cipher =>
cipher
-> (Int, Int, ByteString)
-> ByteString
-> ByteString
-> Int
-> AuthTag
ccm_tag cipher
key (Int
t, Int
q, ByteString
nonce) ByteString
header ByteString
msg Int
taglen