{-# 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 :: Int -> Int -> cipher -> iv -> Maybe (AEAD cipher)
ccmInit t :: Int
t q :: Int
q cipher :: cipher
cipher nonce :: 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 :: Int -> Int -> cipher -> iv -> Maybe (CCM cipher)
ccm_init t :: Int
t q :: Int
q cipher :: cipher
cipher nonce :: 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
== 16
valid_t :: Bool
valid_t = Int
t Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= 4 Bool -> Bool -> Bool
&& Int
t Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= 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
>= 2 Bool -> Bool -> Bool
&& Int
q Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= 8
nonce_len :: Int
nonce_len = 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 :: 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 16 3
ccm_encodeAdditionalLength :: B.ByteString -> B.ByteString
ccm_encodeAdditionalLength :: ByteString -> ByteString
ccm_encodeAdditionalLength s :: 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 -> n -> Bool
forall a. Eq a => a -> a -> Bool
== 0 = ByteString
B.empty
| n
n n -> n -> Bool
forall a. Ord a => a -> a -> Bool
< (2n -> Int -> n
forall a b. (Num a, Integral b) => a -> b -> a
^(16::Int)n -> n -> n
forall a. Num a => a -> a -> a
-2n -> Int -> n
forall a b. (Num a, Integral b) => a -> b -> a
^(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 2 n
n
| n
n n -> n -> Bool
forall a. Ord a => a -> a -> Bool
< (2n -> Int -> n
forall a b. (Num a, Integral b) => a -> b -> a
^(32::Int)) = [Word8] -> ByteString
B.pack (0xffWord8 -> [Word8] -> [Word8]
forall a. a -> [a] -> [a]
:0xfeWord8 -> [Word8] -> [Word8]
forall a. a -> [a] -> [a]
:Int -> n -> [Word8]
forall n. Integral n => Int -> n -> [Word8]
netEncode 4 n
n)
| Bool
otherwise = [Word8] -> ByteString
B.pack (0xffWord8 -> [Word8] -> [Word8]
forall a. a -> [a] -> [a]
:0xffWord8 -> [Word8] -> [Word8]
forall a. a -> [a] -> [a]
:Int -> n -> [Word8]
forall n. Integral n => Int -> n -> [Word8]
netEncode 8 n
n)
pad_zero :: Int -> B.ByteString -> B.ByteString
pad_zero :: Int -> ByteString -> ByteString
pad_zero l :: Int
l s :: 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
- 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
- 1) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
l) 0
_makeIV :: BlockCipher cipher => B.ByteString -> IV cipher
_makeIV :: ByteString -> IV cipher
_makeIV iv :: ByteString
iv = let Just iv' :: 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 :: (Int, Int, ByteString) -> IV cipher
ccm_start_iv (_, q :: Int
q, nonce :: 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
- 1, ByteString
nonce, Int -> Word8 -> ByteString
B.replicate (Int
q Int -> Int -> Int
forall a. Num a => a -> a -> a
- 1) 0, Word8 -> ByteString
B.singleton 1]
ccm_tag_iv :: BlockCipher cipher => (Int, Int, B.ByteString) -> IV cipher
ccm_tag_iv :: (Int, Int, ByteString) -> IV cipher
ccm_tag_iv (_, q :: Int
q, nonce :: 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
- 1, ByteString
nonce, Int -> Word8 -> ByteString
B.replicate Int
q 0]
ccm_crypt :: BlockCipher cipher => cipher -> IV cipher -> B.ByteString -> (B.ByteString, IV cipher)
ccm_crypt :: cipher -> IV cipher -> ByteString -> (ByteString, IV cipher)
ccm_crypt key :: cipher
key iv :: IV cipher
iv src :: ByteString
src = let
blocks :: Int
blocks = (ByteString -> Int
B.length ByteString
src Int -> Int -> Int
forall a. Num a => a -> a -> a
+ 15) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` 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 :: cipher
-> (Int, Int, ByteString)
-> ByteString
-> ByteString
-> Int
-> AuthTag
ccm_tag key :: cipher
key (t :: Int
t, q :: Int
q, nonce :: ByteString
nonce) header :: ByteString
header msg :: ByteString
msg taglen :: 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
> 0 then 64 else 0) Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
+ 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
- 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
- 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 16 (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString
ccm_encodeAdditionalLength ByteString
header, Int -> ByteString -> ByteString
pad_zero 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
- 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 _ (CCM_Header (t :: Int
t, q :: Int
q, nonce :: ByteString
nonce) header :: ByteString
header) src :: 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 _ _ _ = [Char] -> CCM cipher
forall a. HasCallStack => [Char] -> a
error "can't aeadStateAppendHeader anymore, already have real data"
aeadStateEncrypt :: cipher -> CCM cipher -> ByteString -> (ByteString, CCM cipher)
aeadStateEncrypt key :: cipher
key (CCM_Header (t :: Int
t, q :: Int
q, nonce :: ByteString
nonce) header :: ByteString
header) src :: 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 key :: cipher
key (CCM_Enc (t :: Int
t, q :: Int
q, nonce :: ByteString
nonce) header :: ByteString
header iv :: IV cipher
iv msg :: ByteString
msg) src :: ByteString
src = let
(dst :: ByteString
dst, iv' :: 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 _ _ _ = [Char] -> (ByteString, CCM cipher)
forall a. HasCallStack => [Char] -> a
error "can't aeadStateEncrypt anymore, already is in decrypt mode"
aeadStateDecrypt :: cipher -> CCM cipher -> ByteString -> (ByteString, CCM cipher)
aeadStateDecrypt key :: cipher
key (CCM_Header (t :: Int
t, q :: Int
q, nonce :: ByteString
nonce) header :: ByteString
header) src :: 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 key :: cipher
key (CCM_Dec (t :: Int
t, q :: Int
q, nonce :: ByteString
nonce) header :: ByteString
header iv :: IV cipher
iv msg :: ByteString
msg) src :: ByteString
src = let
(dst :: ByteString
dst, iv' :: 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 _ _ _ = [Char] -> (ByteString, CCM cipher)
forall a. HasCallStack => [Char] -> a
error "can't aeadStateDecrypt anymore, already is in encrypt mode"
aeadStateFinalize :: cipher -> CCM cipher -> Int -> AuthTag
aeadStateFinalize key :: cipher
key (CCM_Header (t :: Int
t, q :: Int
q, nonce :: ByteString
nonce) header :: ByteString
header ) taglen :: 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 key :: cipher
key (CCM_Enc (t :: Int
t, q :: Int
q, nonce :: ByteString
nonce) header :: ByteString
header _ msg :: ByteString
msg) taglen :: 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 key :: cipher
key (CCM_Dec (t :: Int
t, q :: Int
q, nonce :: ByteString
nonce) header :: ByteString
header _ msg :: ByteString
msg) taglen :: 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