Merge branch 'cipher-framework'

This commit is contained in:
Vincent Hanquez 2015-04-11 08:28:01 +01:00
commit b08c7a223c
36 changed files with 2716 additions and 60 deletions

9
Crypto/Cipher/AES.hs Normal file
View File

@ -0,0 +1,9 @@
-- |
-- Module : Crypto.Cipher.AES
-- License : BSD-style
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
-- Stability : stable
-- Portability : good
module Crypto.Cipher.AES
(
) where

View File

@ -21,7 +21,6 @@ import Foreign.C.String
data AES data AES
data AESOCB data AESOCB
data AESGCM data AESGCM
------------------------------------------------------------------------ ------------------------------------------------------------------------
foreign import ccall "cryptonite_aes.h cryptonite_aes_initkey" foreign import ccall "cryptonite_aes.h cryptonite_aes_initkey"
c_aes_init :: Ptr AES -> CString -> CUInt -> IO () c_aes_init :: Ptr AES -> CString -> CUInt -> IO ()

60
Crypto/Cipher/Blowfish.hs Normal file
View File

@ -0,0 +1,60 @@
{-# LANGUAGE CPP #-}
-- |
-- Module : Crypto.Cipher.Blowfish
-- License : BSD-style
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
-- Stability : stable
-- Portability : good
--
module Crypto.Cipher.Blowfish
( Blowfish
, Blowfish64
, Blowfish128
, Blowfish256
, Blowfish448
) where
import Crypto.Cipher.Types
import Crypto.Cipher.Blowfish.Primitive
-- | variable keyed blowfish state
newtype Blowfish = Blowfish Context
-- | 64 bit keyed blowfish state
newtype Blowfish64 = Blowfish64 Context
-- | 128 bit keyed blowfish state
newtype Blowfish128 = Blowfish128 Context
-- | 256 bit keyed blowfish state
newtype Blowfish256 = Blowfish256 Context
-- | 448 bit keyed blowfish state
newtype Blowfish448 = Blowfish448 Context
instance Cipher Blowfish where
cipherName _ = "blowfish"
cipherKeySize _ = KeySizeRange 6 56
cipherInit k = Blowfish `fmap` initBlowfish k
instance BlockCipher Blowfish where
blockSize _ = 8
ecbEncrypt (Blowfish bf) = encrypt bf
ecbDecrypt (Blowfish bf) = decrypt bf
#define INSTANCE_CIPHER(CSTR, NAME, KEYSIZE) \
instance Cipher CSTR where \
{ cipherName _ = NAME \
; cipherKeySize _ = KeySizeFixed KEYSIZE \
; cipherInit k = CSTR `fmap` initBlowfish k \
}; \
instance BlockCipher CSTR where \
{ blockSize _ = 8 \
; ecbEncrypt (CSTR bf) = ecbEncryptLegacy encrypt bf \
; ecbDecrypt (CSTR bf) = ecbDecryptLegacy decrypt bf \
};
INSTANCE_CIPHER(Blowfish64, "blowfish64", 8)
INSTANCE_CIPHER(Blowfish128, "blowfish128", 16)
INSTANCE_CIPHER(Blowfish256, "blowfish256", 32)
INSTANCE_CIPHER(Blowfish448, "blowfish448", 56)

View File

@ -0,0 +1,278 @@
-- |
-- Module : Crypto.Cipher.Blowfish.Box
-- License : BSD-style
-- Stability : experimental
-- Portability : Good
{-# LANGUAGE MagicHash #-}
module Crypto.Cipher.Blowfish.Box
( createKeySchedule
) where
import Crypto.Internal.WordArray (mutableArray32FromAddrBE, MutableArray32)
-- | Create a key schedule mutable array of the pbox followed by
-- all the sboxes.
createKeySchedule :: IO MutableArray32
createKeySchedule = mutableArray32FromAddrBE 1042 "\
\\x24\x3f\x6a\x88\x85\xa3\x08\xd3\x13\x19\x8a\x2e\x03\x70\x73\x44\
\\xa4\x09\x38\x22\x29\x9f\x31\xd0\x08\x2e\xfa\x98\xec\x4e\x6c\x89\
\\x45\x28\x21\xe6\x38\xd0\x13\x77\xbe\x54\x66\xcf\x34\xe9\x0c\x6c\
\\xc0\xac\x29\xb7\xc9\x7c\x50\xdd\x3f\x84\xd5\xb5\xb5\x47\x09\x17\
\\x92\x16\xd5\xd9\x89\x79\xfb\x1b\
\\xd1\x31\x0b\xa6\x98\xdf\xb5\xac\x2f\xfd\x72\xdb\xd0\x1a\xdf\xb7\
\\xb8\xe1\xaf\xed\x6a\x26\x7e\x96\xba\x7c\x90\x45\xf1\x2c\x7f\x99\
\\x24\xa1\x99\x47\xb3\x91\x6c\xf7\x08\x01\xf2\xe2\x85\x8e\xfc\x16\
\\x63\x69\x20\xd8\x71\x57\x4e\x69\xa4\x58\xfe\xa3\xf4\x93\x3d\x7e\
\\x0d\x95\x74\x8f\x72\x8e\xb6\x58\x71\x8b\xcd\x58\x82\x15\x4a\xee\
\\x7b\x54\xa4\x1d\xc2\x5a\x59\xb5\x9c\x30\xd5\x39\x2a\xf2\x60\x13\
\\xc5\xd1\xb0\x23\x28\x60\x85\xf0\xca\x41\x79\x18\xb8\xdb\x38\xef\
\\x8e\x79\xdc\xb0\x60\x3a\x18\x0e\x6c\x9e\x0e\x8b\xb0\x1e\x8a\x3e\
\\xd7\x15\x77\xc1\xbd\x31\x4b\x27\x78\xaf\x2f\xda\x55\x60\x5c\x60\
\\xe6\x55\x25\xf3\xaa\x55\xab\x94\x57\x48\x98\x62\x63\xe8\x14\x40\
\\x55\xca\x39\x6a\x2a\xab\x10\xb6\xb4\xcc\x5c\x34\x11\x41\xe8\xce\
\\xa1\x54\x86\xaf\x7c\x72\xe9\x93\xb3\xee\x14\x11\x63\x6f\xbc\x2a\
\\x2b\xa9\xc5\x5d\x74\x18\x31\xf6\xce\x5c\x3e\x16\x9b\x87\x93\x1e\
\\xaf\xd6\xba\x33\x6c\x24\xcf\x5c\x7a\x32\x53\x81\x28\x95\x86\x77\
\\x3b\x8f\x48\x98\x6b\x4b\xb9\xaf\xc4\xbf\xe8\x1b\x66\x28\x21\x93\
\\x61\xd8\x09\xcc\xfb\x21\xa9\x91\x48\x7c\xac\x60\x5d\xec\x80\x32\
\\xef\x84\x5d\x5d\xe9\x85\x75\xb1\xdc\x26\x23\x02\xeb\x65\x1b\x88\
\\x23\x89\x3e\x81\xd3\x96\xac\xc5\x0f\x6d\x6f\xf3\x83\xf4\x42\x39\
\\x2e\x0b\x44\x82\xa4\x84\x20\x04\x69\xc8\xf0\x4a\x9e\x1f\x9b\x5e\
\\x21\xc6\x68\x42\xf6\xe9\x6c\x9a\x67\x0c\x9c\x61\xab\xd3\x88\xf0\
\\x6a\x51\xa0\xd2\xd8\x54\x2f\x68\x96\x0f\xa7\x28\xab\x51\x33\xa3\
\\x6e\xef\x0b\x6c\x13\x7a\x3b\xe4\xba\x3b\xf0\x50\x7e\xfb\x2a\x98\
\\xa1\xf1\x65\x1d\x39\xaf\x01\x76\x66\xca\x59\x3e\x82\x43\x0e\x88\
\\x8c\xee\x86\x19\x45\x6f\x9f\xb4\x7d\x84\xa5\xc3\x3b\x8b\x5e\xbe\
\\xe0\x6f\x75\xd8\x85\xc1\x20\x73\x40\x1a\x44\x9f\x56\xc1\x6a\xa6\
\\x4e\xd3\xaa\x62\x36\x3f\x77\x06\x1b\xfe\xdf\x72\x42\x9b\x02\x3d\
\\x37\xd0\xd7\x24\xd0\x0a\x12\x48\xdb\x0f\xea\xd3\x49\xf1\xc0\x9b\
\\x07\x53\x72\xc9\x80\x99\x1b\x7b\x25\xd4\x79\xd8\xf6\xe8\xde\xf7\
\\xe3\xfe\x50\x1a\xb6\x79\x4c\x3b\x97\x6c\xe0\xbd\x04\xc0\x06\xba\
\\xc1\xa9\x4f\xb6\x40\x9f\x60\xc4\x5e\x5c\x9e\xc2\x19\x6a\x24\x63\
\\x68\xfb\x6f\xaf\x3e\x6c\x53\xb5\x13\x39\xb2\xeb\x3b\x52\xec\x6f\
\\x6d\xfc\x51\x1f\x9b\x30\x95\x2c\xcc\x81\x45\x44\xaf\x5e\xbd\x09\
\\xbe\xe3\xd0\x04\xde\x33\x4a\xfd\x66\x0f\x28\x07\x19\x2e\x4b\xb3\
\\xc0\xcb\xa8\x57\x45\xc8\x74\x0f\xd2\x0b\x5f\x39\xb9\xd3\xfb\xdb\
\\x55\x79\xc0\xbd\x1a\x60\x32\x0a\xd6\xa1\x00\xc6\x40\x2c\x72\x79\
\\x67\x9f\x25\xfe\xfb\x1f\xa3\xcc\x8e\xa5\xe9\xf8\xdb\x32\x22\xf8\
\\x3c\x75\x16\xdf\xfd\x61\x6b\x15\x2f\x50\x1e\xc8\xad\x05\x52\xab\
\\x32\x3d\xb5\xfa\xfd\x23\x87\x60\x53\x31\x7b\x48\x3e\x00\xdf\x82\
\\x9e\x5c\x57\xbb\xca\x6f\x8c\xa0\x1a\x87\x56\x2e\xdf\x17\x69\xdb\
\\xd5\x42\xa8\xf6\x28\x7e\xff\xc3\xac\x67\x32\xc6\x8c\x4f\x55\x73\
\\x69\x5b\x27\xb0\xbb\xca\x58\xc8\xe1\xff\xa3\x5d\xb8\xf0\x11\xa0\
\\x10\xfa\x3d\x98\xfd\x21\x83\xb8\x4a\xfc\xb5\x6c\x2d\xd1\xd3\x5b\
\\x9a\x53\xe4\x79\xb6\xf8\x45\x65\xd2\x8e\x49\xbc\x4b\xfb\x97\x90\
\\xe1\xdd\xf2\xda\xa4\xcb\x7e\x33\x62\xfb\x13\x41\xce\xe4\xc6\xe8\
\\xef\x20\xca\xda\x36\x77\x4c\x01\xd0\x7e\x9e\xfe\x2b\xf1\x1f\xb4\
\\x95\xdb\xda\x4d\xae\x90\x91\x98\xea\xad\x8e\x71\x6b\x93\xd5\xa0\
\\xd0\x8e\xd1\xd0\xaf\xc7\x25\xe0\x8e\x3c\x5b\x2f\x8e\x75\x94\xb7\
\\x8f\xf6\xe2\xfb\xf2\x12\x2b\x64\x88\x88\xb8\x12\x90\x0d\xf0\x1c\
\\x4f\xad\x5e\xa0\x68\x8f\xc3\x1c\xd1\xcf\xf1\x91\xb3\xa8\xc1\xad\
\\x2f\x2f\x22\x18\xbe\x0e\x17\x77\xea\x75\x2d\xfe\x8b\x02\x1f\xa1\
\\xe5\xa0\xcc\x0f\xb5\x6f\x74\xe8\x18\xac\xf3\xd6\xce\x89\xe2\x99\
\\xb4\xa8\x4f\xe0\xfd\x13\xe0\xb7\x7c\xc4\x3b\x81\xd2\xad\xa8\xd9\
\\x16\x5f\xa2\x66\x80\x95\x77\x05\x93\xcc\x73\x14\x21\x1a\x14\x77\
\\xe6\xad\x20\x65\x77\xb5\xfa\x86\xc7\x54\x42\xf5\xfb\x9d\x35\xcf\
\\xeb\xcd\xaf\x0c\x7b\x3e\x89\xa0\xd6\x41\x1b\xd3\xae\x1e\x7e\x49\
\\x00\x25\x0e\x2d\x20\x71\xb3\x5e\x22\x68\x00\xbb\x57\xb8\xe0\xaf\
\\x24\x64\x36\x9b\xf0\x09\xb9\x1e\x55\x63\x91\x1d\x59\xdf\xa6\xaa\
\\x78\xc1\x43\x89\xd9\x5a\x53\x7f\x20\x7d\x5b\xa2\x02\xe5\xb9\xc5\
\\x83\x26\x03\x76\x62\x95\xcf\xa9\x11\xc8\x19\x68\x4e\x73\x4a\x41\
\\xb3\x47\x2d\xca\x7b\x14\xa9\x4a\x1b\x51\x00\x52\x9a\x53\x29\x15\
\\xd6\x0f\x57\x3f\xbc\x9b\xc6\xe4\x2b\x60\xa4\x76\x81\xe6\x74\x00\
\\x08\xba\x6f\xb5\x57\x1b\xe9\x1f\xf2\x96\xec\x6b\x2a\x0d\xd9\x15\
\\xb6\x63\x65\x21\xe7\xb9\xf9\xb6\xff\x34\x05\x2e\xc5\x85\x56\x64\
\\x53\xb0\x2d\x5d\xa9\x9f\x8f\xa1\x08\xba\x47\x99\x6e\x85\x07\x6a\
\\x4b\x7a\x70\xe9\xb5\xb3\x29\x44\xdb\x75\x09\x2e\xc4\x19\x26\x23\
\\xad\x6e\xa6\xb0\x49\xa7\xdf\x7d\x9c\xee\x60\xb8\x8f\xed\xb2\x66\
\\xec\xaa\x8c\x71\x69\x9a\x17\xff\x56\x64\x52\x6c\xc2\xb1\x9e\xe1\
\\x19\x36\x02\xa5\x75\x09\x4c\x29\xa0\x59\x13\x40\xe4\x18\x3a\x3e\
\\x3f\x54\x98\x9a\x5b\x42\x9d\x65\x6b\x8f\xe4\xd6\x99\xf7\x3f\xd6\
\\xa1\xd2\x9c\x07\xef\xe8\x30\xf5\x4d\x2d\x38\xe6\xf0\x25\x5d\xc1\
\\x4c\xdd\x20\x86\x84\x70\xeb\x26\x63\x82\xe9\xc6\x02\x1e\xcc\x5e\
\\x09\x68\x6b\x3f\x3e\xba\xef\xc9\x3c\x97\x18\x14\x6b\x6a\x70\xa1\
\\x68\x7f\x35\x84\x52\xa0\xe2\x86\xb7\x9c\x53\x05\xaa\x50\x07\x37\
\\x3e\x07\x84\x1c\x7f\xde\xae\x5c\x8e\x7d\x44\xec\x57\x16\xf2\xb8\
\\xb0\x3a\xda\x37\xf0\x50\x0c\x0d\xf0\x1c\x1f\x04\x02\x00\xb3\xff\
\\xae\x0c\xf5\x1a\x3c\xb5\x74\xb2\x25\x83\x7a\x58\xdc\x09\x21\xbd\
\\xd1\x91\x13\xf9\x7c\xa9\x2f\xf6\x94\x32\x47\x73\x22\xf5\x47\x01\
\\x3a\xe5\xe5\x81\x37\xc2\xda\xdc\xc8\xb5\x76\x34\x9a\xf3\xdd\xa7\
\\xa9\x44\x61\x46\x0f\xd0\x03\x0e\xec\xc8\xc7\x3e\xa4\x75\x1e\x41\
\\xe2\x38\xcd\x99\x3b\xea\x0e\x2f\x32\x80\xbb\xa1\x18\x3e\xb3\x31\
\\x4e\x54\x8b\x38\x4f\x6d\xb9\x08\x6f\x42\x0d\x03\xf6\x0a\x04\xbf\
\\x2c\xb8\x12\x90\x24\x97\x7c\x79\x56\x79\xb0\x72\xbc\xaf\x89\xaf\
\\xde\x9a\x77\x1f\xd9\x93\x08\x10\xb3\x8b\xae\x12\xdc\xcf\x3f\x2e\
\\x55\x12\x72\x1f\x2e\x6b\x71\x24\x50\x1a\xdd\xe6\x9f\x84\xcd\x87\
\\x7a\x58\x47\x18\x74\x08\xda\x17\xbc\x9f\x9a\xbc\xe9\x4b\x7d\x8c\
\\xec\x7a\xec\x3a\xdb\x85\x1d\xfa\x63\x09\x43\x66\xc4\x64\xc3\xd2\
\\xef\x1c\x18\x47\x32\x15\xd9\x08\xdd\x43\x3b\x37\x24\xc2\xba\x16\
\\x12\xa1\x4d\x43\x2a\x65\xc4\x51\x50\x94\x00\x02\x13\x3a\xe4\xdd\
\\x71\xdf\xf8\x9e\x10\x31\x4e\x55\x81\xac\x77\xd6\x5f\x11\x19\x9b\
\\x04\x35\x56\xf1\xd7\xa3\xc7\x6b\x3c\x11\x18\x3b\x59\x24\xa5\x09\
\\xf2\x8f\xe6\xed\x97\xf1\xfb\xfa\x9e\xba\xbf\x2c\x1e\x15\x3c\x6e\
\\x86\xe3\x45\x70\xea\xe9\x6f\xb1\x86\x0e\x5e\x0a\x5a\x3e\x2a\xb3\
\\x77\x1f\xe7\x1c\x4e\x3d\x06\xfa\x29\x65\xdc\xb9\x99\xe7\x1d\x0f\
\\x80\x3e\x89\xd6\x52\x66\xc8\x25\x2e\x4c\xc9\x78\x9c\x10\xb3\x6a\
\\xc6\x15\x0e\xba\x94\xe2\xea\x78\xa5\xfc\x3c\x53\x1e\x0a\x2d\xf4\
\\xf2\xf7\x4e\xa7\x36\x1d\x2b\x3d\x19\x39\x26\x0f\x19\xc2\x79\x60\
\\x52\x23\xa7\x08\xf7\x13\x12\xb6\xeb\xad\xfe\x6e\xea\xc3\x1f\x66\
\\xe3\xbc\x45\x95\xa6\x7b\xc8\x83\xb1\x7f\x37\xd1\x01\x8c\xff\x28\
\\xc3\x32\xdd\xef\xbe\x6c\x5a\xa5\x65\x58\x21\x85\x68\xab\x98\x02\
\\xee\xce\xa5\x0f\xdb\x2f\x95\x3b\x2a\xef\x7d\xad\x5b\x6e\x2f\x84\
\\x15\x21\xb6\x28\x29\x07\x61\x70\xec\xdd\x47\x75\x61\x9f\x15\x10\
\\x13\xcc\xa8\x30\xeb\x61\xbd\x96\x03\x34\xfe\x1e\xaa\x03\x63\xcf\
\\xb5\x73\x5c\x90\x4c\x70\xa2\x39\xd5\x9e\x9e\x0b\xcb\xaa\xde\x14\
\\xee\xcc\x86\xbc\x60\x62\x2c\xa7\x9c\xab\x5c\xab\xb2\xf3\x84\x6e\
\\x64\x8b\x1e\xaf\x19\xbd\xf0\xca\xa0\x23\x69\xb9\x65\x5a\xbb\x50\
\\x40\x68\x5a\x32\x3c\x2a\xb4\xb3\x31\x9e\xe9\xd5\xc0\x21\xb8\xf7\
\\x9b\x54\x0b\x19\x87\x5f\xa0\x99\x95\xf7\x99\x7e\x62\x3d\x7d\xa8\
\\xf8\x37\x88\x9a\x97\xe3\x2d\x77\x11\xed\x93\x5f\x16\x68\x12\x81\
\\x0e\x35\x88\x29\xc7\xe6\x1f\xd6\x96\xde\xdf\xa1\x78\x58\xba\x99\
\\x57\xf5\x84\xa5\x1b\x22\x72\x63\x9b\x83\xc3\xff\x1a\xc2\x46\x96\
\\xcd\xb3\x0a\xeb\x53\x2e\x30\x54\x8f\xd9\x48\xe4\x6d\xbc\x31\x28\
\\x58\xeb\xf2\xef\x34\xc6\xff\xea\xfe\x28\xed\x61\xee\x7c\x3c\x73\
\\x5d\x4a\x14\xd9\xe8\x64\xb7\xe3\x42\x10\x5d\x14\x20\x3e\x13\xe0\
\\x45\xee\xe2\xb6\xa3\xaa\xab\xea\xdb\x6c\x4f\x15\xfa\xcb\x4f\xd0\
\\xc7\x42\xf4\x42\xef\x6a\xbb\xb5\x65\x4f\x3b\x1d\x41\xcd\x21\x05\
\\xd8\x1e\x79\x9e\x86\x85\x4d\xc7\xe4\x4b\x47\x6a\x3d\x81\x62\x50\
\\xcf\x62\xa1\xf2\x5b\x8d\x26\x46\xfc\x88\x83\xa0\xc1\xc7\xb6\xa3\
\\x7f\x15\x24\xc3\x69\xcb\x74\x92\x47\x84\x8a\x0b\x56\x92\xb2\x85\
\\x09\x5b\xbf\x00\xad\x19\x48\x9d\x14\x62\xb1\x74\x23\x82\x0e\x00\
\\x58\x42\x8d\x2a\x0c\x55\xf5\xea\x1d\xad\xf4\x3e\x23\x3f\x70\x61\
\\x33\x72\xf0\x92\x8d\x93\x7e\x41\xd6\x5f\xec\xf1\x6c\x22\x3b\xdb\
\\x7c\xde\x37\x59\xcb\xee\x74\x60\x40\x85\xf2\xa7\xce\x77\x32\x6e\
\\xa6\x07\x80\x84\x19\xf8\x50\x9e\xe8\xef\xd8\x55\x61\xd9\x97\x35\
\\xa9\x69\xa7\xaa\xc5\x0c\x06\xc2\x5a\x04\xab\xfc\x80\x0b\xca\xdc\
\\x9e\x44\x7a\x2e\xc3\x45\x34\x84\xfd\xd5\x67\x05\x0e\x1e\x9e\xc9\
\\xdb\x73\xdb\xd3\x10\x55\x88\xcd\x67\x5f\xda\x79\xe3\x67\x43\x40\
\\xc5\xc4\x34\x65\x71\x3e\x38\xd8\x3d\x28\xf8\x9e\xf1\x6d\xff\x20\
\\x15\x3e\x21\xe7\x8f\xb0\x3d\x4a\xe6\xe3\x9f\x2b\xdb\x83\xad\xf7\
\\xe9\x3d\x5a\x68\x94\x81\x40\xf7\xf6\x4c\x26\x1c\x94\x69\x29\x34\
\\x41\x15\x20\xf7\x76\x02\xd4\xf7\xbc\xf4\x6b\x2e\xd4\xa2\x00\x68\
\\xd4\x08\x24\x71\x33\x20\xf4\x6a\x43\xb7\xd4\xb7\x50\x00\x61\xaf\
\\x1e\x39\xf6\x2e\x97\x24\x45\x46\x14\x21\x4f\x74\xbf\x8b\x88\x40\
\\x4d\x95\xfc\x1d\x96\xb5\x91\xaf\x70\xf4\xdd\xd3\x66\xa0\x2f\x45\
\\xbf\xbc\x09\xec\x03\xbd\x97\x85\x7f\xac\x6d\xd0\x31\xcb\x85\x04\
\\x96\xeb\x27\xb3\x55\xfd\x39\x41\xda\x25\x47\xe6\xab\xca\x0a\x9a\
\\x28\x50\x78\x25\x53\x04\x29\xf4\x0a\x2c\x86\xda\xe9\xb6\x6d\xfb\
\\x68\xdc\x14\x62\xd7\x48\x69\x00\x68\x0e\xc0\xa4\x27\xa1\x8d\xee\
\\x4f\x3f\xfe\xa2\xe8\x87\xad\x8c\xb5\x8c\xe0\x06\x7a\xf4\xd6\xb6\
\\xaa\xce\x1e\x7c\xd3\x37\x5f\xec\xce\x78\xa3\x99\x40\x6b\x2a\x42\
\\x20\xfe\x9e\x35\xd9\xf3\x85\xb9\xee\x39\xd7\xab\x3b\x12\x4e\x8b\
\\x1d\xc9\xfa\xf7\x4b\x6d\x18\x56\x26\xa3\x66\x31\xea\xe3\x97\xb2\
\\x3a\x6e\xfa\x74\xdd\x5b\x43\x32\x68\x41\xe7\xf7\xca\x78\x20\xfb\
\\xfb\x0a\xf5\x4e\xd8\xfe\xb3\x97\x45\x40\x56\xac\xba\x48\x95\x27\
\\x55\x53\x3a\x3a\x20\x83\x8d\x87\xfe\x6b\xa9\xb7\xd0\x96\x95\x4b\
\\x55\xa8\x67\xbc\xa1\x15\x9a\x58\xcc\xa9\x29\x63\x99\xe1\xdb\x33\
\\xa6\x2a\x4a\x56\x3f\x31\x25\xf9\x5e\xf4\x7e\x1c\x90\x29\x31\x7c\
\\xfd\xf8\xe8\x02\x04\x27\x2f\x70\x80\xbb\x15\x5c\x05\x28\x2c\xe3\
\\x95\xc1\x15\x48\xe4\xc6\x6d\x22\x48\xc1\x13\x3f\xc7\x0f\x86\xdc\
\\x07\xf9\xc9\xee\x41\x04\x1f\x0f\x40\x47\x79\xa4\x5d\x88\x6e\x17\
\\x32\x5f\x51\xeb\xd5\x9b\xc0\xd1\xf2\xbc\xc1\x8f\x41\x11\x35\x64\
\\x25\x7b\x78\x34\x60\x2a\x9c\x60\xdf\xf8\xe8\xa3\x1f\x63\x6c\x1b\
\\x0e\x12\xb4\xc2\x02\xe1\x32\x9e\xaf\x66\x4f\xd1\xca\xd1\x81\x15\
\\x6b\x23\x95\xe0\x33\x3e\x92\xe1\x3b\x24\x0b\x62\xee\xbe\xb9\x22\
\\x85\xb2\xa2\x0e\xe6\xba\x0d\x99\xde\x72\x0c\x8c\x2d\xa2\xf7\x28\
\\xd0\x12\x78\x45\x95\xb7\x94\xfd\x64\x7d\x08\x62\xe7\xcc\xf5\xf0\
\\x54\x49\xa3\x6f\x87\x7d\x48\xfa\xc3\x9d\xfd\x27\xf3\x3e\x8d\x1e\
\\x0a\x47\x63\x41\x99\x2e\xff\x74\x3a\x6f\x6e\xab\xf4\xf8\xfd\x37\
\\xa8\x12\xdc\x60\xa1\xeb\xdd\xf8\x99\x1b\xe1\x4c\xdb\x6e\x6b\x0d\
\\xc6\x7b\x55\x10\x6d\x67\x2c\x37\x27\x65\xd4\x3b\xdc\xd0\xe8\x04\
\\xf1\x29\x0d\xc7\xcc\x00\xff\xa3\xb5\x39\x0f\x92\x69\x0f\xed\x0b\
\\x66\x7b\x9f\xfb\xce\xdb\x7d\x9c\xa0\x91\xcf\x0b\xd9\x15\x5e\xa3\
\\xbb\x13\x2f\x88\x51\x5b\xad\x24\x7b\x94\x79\xbf\x76\x3b\xd6\xeb\
\\x37\x39\x2e\xb3\xcc\x11\x59\x79\x80\x26\xe2\x97\xf4\x2e\x31\x2d\
\\x68\x42\xad\xa7\xc6\x6a\x2b\x3b\x12\x75\x4c\xcc\x78\x2e\xf1\x1c\
\\x6a\x12\x42\x37\xb7\x92\x51\xe7\x06\xa1\xbb\xe6\x4b\xfb\x63\x50\
\\x1a\x6b\x10\x18\x11\xca\xed\xfa\x3d\x25\xbd\xd8\xe2\xe1\xc3\xc9\
\\x44\x42\x16\x59\x0a\x12\x13\x86\xd9\x0c\xec\x6e\xd5\xab\xea\x2a\
\\x64\xaf\x67\x4e\xda\x86\xa8\x5f\xbe\xbf\xe9\x88\x64\xe4\xc3\xfe\
\\x9d\xbc\x80\x57\xf0\xf7\xc0\x86\x60\x78\x7b\xf8\x60\x03\x60\x4d\
\\xd1\xfd\x83\x46\xf6\x38\x1f\xb0\x77\x45\xae\x04\xd7\x36\xfc\xcc\
\\x83\x42\x6b\x33\xf0\x1e\xab\x71\xb0\x80\x41\x87\x3c\x00\x5e\x5f\
\\x77\xa0\x57\xbe\xbd\xe8\xae\x24\x55\x46\x42\x99\xbf\x58\x2e\x61\
\\x4e\x58\xf4\x8f\xf2\xdd\xfd\xa2\xf4\x74\xef\x38\x87\x89\xbd\xc2\
\\x53\x66\xf9\xc3\xc8\xb3\x8e\x74\xb4\x75\xf2\x55\x46\xfc\xd9\xb9\
\\x7a\xeb\x26\x61\x8b\x1d\xdf\x84\x84\x6a\x0e\x79\x91\x5f\x95\xe2\
\\x46\x6e\x59\x8e\x20\xb4\x57\x70\x8c\xd5\x55\x91\xc9\x02\xde\x4c\
\\xb9\x0b\xac\xe1\xbb\x82\x05\xd0\x11\xa8\x62\x48\x75\x74\xa9\x9e\
\\xb7\x7f\x19\xb6\xe0\xa9\xdc\x09\x66\x2d\x09\xa1\xc4\x32\x46\x33\
\\xe8\x5a\x1f\x02\x09\xf0\xbe\x8c\x4a\x99\xa0\x25\x1d\x6e\xfe\x10\
\\x1a\xb9\x3d\x1d\x0b\xa5\xa4\xdf\xa1\x86\xf2\x0f\x28\x68\xf1\x69\
\\xdc\xb7\xda\x83\x57\x39\x06\xfe\xa1\xe2\xce\x9b\x4f\xcd\x7f\x52\
\\x50\x11\x5e\x01\xa7\x06\x83\xfa\xa0\x02\xb5\xc4\x0d\xe6\xd0\x27\
\\x9a\xf8\x8c\x27\x77\x3f\x86\x41\xc3\x60\x4c\x06\x61\xa8\x06\xb5\
\\xf0\x17\x7a\x28\xc0\xf5\x86\xe0\x00\x60\x58\xaa\x30\xdc\x7d\x62\
\\x11\xe6\x9e\xd7\x23\x38\xea\x63\x53\xc2\xdd\x94\xc2\xc2\x16\x34\
\\xbb\xcb\xee\x56\x90\xbc\xb6\xde\xeb\xfc\x7d\xa1\xce\x59\x1d\x76\
\\x6f\x05\xe4\x09\x4b\x7c\x01\x88\x39\x72\x0a\x3d\x7c\x92\x7c\x24\
\\x86\xe3\x72\x5f\x72\x4d\x9d\xb9\x1a\xc1\x5b\xb4\xd3\x9e\xb8\xfc\
\\xed\x54\x55\x78\x08\xfc\xa5\xb5\xd8\x3d\x7c\xd3\x4d\xad\x0f\xc4\
\\x1e\x50\xef\x5e\xb1\x61\xe6\xf8\xa2\x85\x14\xd9\x6c\x51\x13\x3c\
\\x6f\xd5\xc7\xe7\x56\xe1\x4e\xc4\x36\x2a\xbf\xce\xdd\xc6\xc8\x37\
\\xd7\x9a\x32\x34\x92\x63\x82\x12\x67\x0e\xfa\x8e\x40\x60\x00\xe0\
\\x3a\x39\xce\x37\xd3\xfa\xf5\xcf\xab\xc2\x77\x37\x5a\xc5\x2d\x1b\
\\x5c\xb0\x67\x9e\x4f\xa3\x37\x42\xd3\x82\x27\x40\x99\xbc\x9b\xbe\
\\xd5\x11\x8e\x9d\xbf\x0f\x73\x15\xd6\x2d\x1c\x7e\xc7\x00\xc4\x7b\
\\xb7\x8c\x1b\x6b\x21\xa1\x90\x45\xb2\x6e\xb1\xbe\x6a\x36\x6e\xb4\
\\x57\x48\xab\x2f\xbc\x94\x6e\x79\xc6\xa3\x76\xd2\x65\x49\xc2\xc8\
\\x53\x0f\xf8\xee\x46\x8d\xde\x7d\xd5\x73\x0a\x1d\x4c\xd0\x4d\xc6\
\\x29\x39\xbb\xdb\xa9\xba\x46\x50\xac\x95\x26\xe8\xbe\x5e\xe3\x04\
\\xa1\xfa\xd5\xf0\x6a\x2d\x51\x9a\x63\xef\x8c\xe2\x9a\x86\xee\x22\
\\xc0\x89\xc2\xb8\x43\x24\x2e\xf6\xa5\x1e\x03\xaa\x9c\xf2\xd0\xa4\
\\x83\xc0\x61\xba\x9b\xe9\x6a\x4d\x8f\xe5\x15\x50\xba\x64\x5b\xd6\
\\x28\x26\xa2\xf9\xa7\x3a\x3a\xe1\x4b\xa9\x95\x86\xef\x55\x62\xe9\
\\xc7\x2f\xef\xd3\xf7\x52\xf7\xda\x3f\x04\x6f\x69\x77\xfa\x0a\x59\
\\x80\xe4\xa9\x15\x87\xb0\x86\x01\x9b\x09\xe6\xad\x3b\x3e\xe5\x93\
\\xe9\x90\xfd\x5a\x9e\x34\xd7\x97\x2c\xf0\xb7\xd9\x02\x2b\x8b\x51\
\\x96\xd5\xac\x3a\x01\x7d\xa6\x7d\xd1\xcf\x3e\xd6\x7c\x7d\x2d\x28\
\\x1f\x9f\x25\xcf\xad\xf2\xb8\x9b\x5a\xd6\xb4\x72\x5a\x88\xf5\x4c\
\\xe0\x29\xac\x71\xe0\x19\xa5\xe6\x47\xb0\xac\xfd\xed\x93\xfa\x9b\
\\xe8\xd3\xc4\x8d\x28\x3b\x57\xcc\xf8\xd5\x66\x29\x79\x13\x2e\x28\
\\x78\x5f\x01\x91\xed\x75\x60\x55\xf7\x96\x0e\x44\xe3\xd3\x5e\x8c\
\\x15\x05\x6d\xd4\x88\xf4\x6d\xba\x03\xa1\x61\x25\x05\x64\xf0\xbd\
\\xc3\xeb\x9e\x15\x3c\x90\x57\xa2\x97\x27\x1a\xec\xa9\x3a\x07\x2a\
\\x1b\x3f\x6d\x9b\x1e\x63\x21\xf5\xf5\x9c\x66\xfb\x26\xdc\xf3\x19\
\\x75\x33\xd9\x28\xb1\x55\xfd\xf5\x03\x56\x34\x82\x8a\xba\x3c\xbb\
\\x28\x51\x77\x11\xc2\x0a\xd9\xf8\xab\xcc\x51\x67\xcc\xad\x92\x5f\
\\x4d\xe8\x17\x51\x38\x30\xdc\x8e\x37\x9d\x58\x62\x93\x20\xf9\x91\
\\xea\x7a\x90\xc2\xfb\x3e\x7b\xce\x51\x21\xce\x64\x77\x4f\xbe\x32\
\\xa8\xb6\xe3\x7e\xc3\x29\x3d\x46\x48\xde\x53\x69\x64\x13\xe6\x80\
\\xa2\xae\x08\x10\xdd\x6d\xb2\x24\x69\x85\x2d\xfd\x09\x07\x21\x66\
\\xb3\x9a\x46\x0a\x64\x45\xc0\xdd\x58\x6c\xde\xcf\x1c\x20\xc8\xae\
\\x5b\xbe\xf7\xdd\x1b\x58\x8d\x40\xcc\xd2\x01\x7f\x6b\xb4\xe3\xbb\
\\xdd\xa2\x6a\x7e\x3a\x59\xff\x45\x3e\x35\x0a\x44\xbc\xb4\xcd\xd5\
\\x72\xea\xce\xa8\xfa\x64\x84\xbb\x8d\x66\x12\xae\xbf\x3c\x6f\x47\
\\xd2\x9b\xe4\x63\x54\x2f\x5d\x9e\xae\xc2\x77\x1b\xf6\x4e\x63\x70\
\\x74\x0e\x0d\x8d\xe7\x5b\x13\x57\xf8\x72\x16\x71\xaf\x53\x7d\x5d\
\\x40\x40\xcb\x08\x4e\xb4\xe2\xcc\x34\xd2\x46\x6a\x01\x15\xaf\x84\
\\xe1\xb0\x04\x28\x95\x98\x3a\x1d\x06\xb8\x9f\xb4\xce\x6e\xa0\x48\
\\x6f\x3f\x3b\x82\x35\x20\xab\x82\x01\x1a\x1d\x4b\x27\x72\x27\xf8\
\\x61\x15\x60\xb1\xe7\x93\x3f\xdc\xbb\x3a\x79\x2b\x34\x45\x25\xbd\
\\xa0\x88\x39\xe1\x51\xce\x79\x4b\x2f\x32\xc9\xb7\xa0\x1f\xba\xc9\
\\xe0\x1c\xc8\x7e\xbc\xc7\xd1\xf6\xcf\x01\x11\xc3\xa1\xe8\xaa\xc7\
\\x1a\x90\x87\x49\xd4\x4f\xbd\x9a\xd0\xda\xde\xcb\xd5\x0a\xda\x38\
\\x03\x39\xc3\x2a\xc6\x91\x36\x67\x8d\xf9\x31\x7c\xe0\xb1\x2b\x4f\
\\xf7\x9e\x59\xb7\x43\xf5\xbb\x3a\xf2\xd5\x19\xff\x27\xd9\x45\x9c\
\\xbf\x97\x22\x2c\x15\xe6\xfc\x2a\x0f\x91\xfc\x71\x9b\x94\x15\x25\
\\xfa\xe5\x93\x61\xce\xb6\x9c\xeb\xc2\xa8\x64\x59\x12\xba\xa8\xd1\
\\xb6\xc1\x07\x5e\xe3\x05\x6a\x0c\x10\xd2\x50\x65\xcb\x03\xa4\x42\
\\xe0\xec\x6e\x0e\x16\x98\xdb\x3b\x4c\x98\xa0\xbe\x32\x78\xe9\x64\
\\x9f\x1f\x95\x32\xe0\xd3\x92\xdf\xd3\xa0\x34\x2b\x89\x71\xf2\x1e\
\\x1b\x0a\x74\x41\x4b\xa3\x34\x8c\xc5\xbe\x71\x20\xc3\x76\x32\xd8\
\\xdf\x35\x9f\x8d\x9b\x99\x2f\x2e\xe6\x0b\x6f\x47\x0f\xe3\xf1\x1d\
\\xe5\x4c\xda\x54\x1e\xda\xd8\x91\xce\x62\x79\xcf\xcd\x3e\x7e\x6f\
\\x16\x18\xb1\x66\xfd\x2c\x1d\x05\x84\x8f\xd2\xc5\xf6\xfb\x22\x99\
\\xf5\x23\xf3\x57\xa6\x32\x76\x23\x93\xa8\x35\x31\x56\xcc\xcd\x02\
\\xac\xf0\x81\x62\x5a\x75\xeb\xb5\x6e\x16\x36\x97\x88\xd2\x73\xcc\
\\xde\x96\x62\x92\x81\xb9\x49\xd0\x4c\x50\x90\x1b\x71\xc6\x56\x14\
\\xe6\xc6\xc7\xbd\x32\x7a\x14\x0a\x45\xe1\xd0\x06\xc3\xf2\x7b\x9a\
\\xc9\xaa\x53\xfd\x62\xa8\x0f\x00\xbb\x25\xbf\xe2\x35\xbd\xd2\xf6\
\\x71\x12\x69\x05\xb2\x04\x02\x22\xb6\xcb\xcf\x7c\xcd\x76\x9c\x2b\
\\x53\x11\x3e\xc0\x16\x40\xe3\xd3\x38\xab\xbd\x60\x25\x47\xad\xf0\
\\xba\x38\x20\x9c\xf7\x46\xce\x76\x77\xaf\xa1\xc5\x20\x75\x60\x60\
\\x85\xcb\xfe\x4e\x8a\xe8\x8d\xd8\x7a\xaa\xf9\xb0\x4c\xf9\xaa\x7e\
\\x19\x48\xc2\x5c\x02\xfb\x8a\x8c\x01\xc3\x6a\xe4\xd6\xeb\xe1\xf9\
\\x90\xd4\xf8\x69\xa6\x5c\xde\xa0\x3f\x09\x25\x2d\xc2\x08\xe6\x9f\
\\xb7\x4e\x61\x32\xce\x77\xe2\x5b\x57\x8f\xdf\xe3\x3a\xc3\x72\xe6\
\"#

View File

@ -0,0 +1,143 @@
-- |
-- Module : Crypto.Cipher.Blowfish.Primitive
-- License : BSD-style
-- Stability : experimental
-- Portability : Good
-- Rewritten by Vincent Hanquez (c) 2015
--
-- Original code:
-- Crypto.Cipher.Blowfish.Primitive, copyright (c) 2012 Stijn van Drongelen
-- based on: BlowfishAux.hs (C) 2002 HardCore SoftWare, Doug Hoyte
-- (as found in Crypto-4.2.4)
module Crypto.Cipher.Blowfish.Primitive
( Context
, initBlowfish
, encrypt
, decrypt
) where
import Control.Monad (forM_)
import Data.Bits
import Data.Word
import qualified Data.ByteString as B
import Crypto.Error
import Crypto.Internal.Compat
import Crypto.Internal.ByteArray
import Crypto.Internal.Words
import Crypto.Internal.WordArray
import Crypto.Cipher.Blowfish.Box
-- | variable keyed blowfish state
data Context = BF (Int -> Word32) -- p
(Int -> Word32) -- sbox0
(Int -> Word32) -- sbox1
(Int -> Word32) -- sbox2
(Int -> Word32) -- sbox2
encrypt, decrypt :: ByteArray ba => Context -> ba -> ba
encrypt = cipher
decrypt = cipher . decryptContext
decryptContext :: Context -> Context
decryptContext (BF p s0 s1 s2 s3) = BF (\i -> p (17-i)) s0 s1 s2 s3
cipher :: ByteArray ba => Context -> ba -> ba
cipher ctx b
| byteArrayLength b == 0 = empty
| byteArrayLength b `mod` 8 /= 0 = error "invalid data length"
| otherwise = byteArrayMapAsWord64 (coreCrypto ctx) b
initBlowfish :: ByteArray key => key -> CryptoFailable Context
initBlowfish key
| len > (448 `div` 8) = CryptoFailed $ CryptoError_KeySizeInvalid
| len == 0 = keyFromByteString (B.replicate (18*4) 0)
| otherwise = keyFromByteString . B.pack . take (18*4) . cycle . B.unpack . byteArrayToBS $ key
where len = byteArrayLength key
keyFromByteString :: B.ByteString -> CryptoFailable Context
keyFromByteString k
| B.length k /= (18 * 4) = CryptoFailed CryptoError_KeySizeInvalid
| otherwise = CryptoPassed . makeKeySchedule . w8tow32 . B.unpack $ k
where
w8tow32 :: [Word8] -> [Word32]
w8tow32 [] = []
w8tow32 (a:b:c:d:xs) = ( (fromIntegral a `shiftL` 24) .|.
(fromIntegral b `shiftL` 16) .|.
(fromIntegral c `shiftL` 8) .|.
(fromIntegral d) ) : w8tow32 xs
w8tow32 _ = error $ "internal error: Crypto.Cipher.Blowfish:keyFromByteString"
coreCrypto :: Context -> Word64 -> Word64
coreCrypto (BF p s0 s1 s2 s3) input = doRound input 0
where
-- transform the input @i over 16 rounds
doRound :: Word64 -> Int -> Word64
doRound i roundIndex
| roundIndex == 16 =
let final = (fromIntegral (p 16) `shiftL` 32) .|. fromIntegral (p 17)
in rotateL (i `xor` final) 32
| otherwise =
let newr = fromIntegral (i `shiftR` 32) `xor` (p roundIndex)
newi = ((i `shiftL` 32) `xor` (f newr)) .|. (fromIntegral newr)
in doRound newi (roundIndex+1)
f :: Word32 -> Word64
f t = let a = s0 (fromIntegral $ (t `shiftR` 24) .&. 0xff)
b = s1 (fromIntegral $ (t `shiftR` 16) .&. 0xff)
c = s2 (fromIntegral $ (t `shiftR` 8) .&. 0xff)
d = s3 (fromIntegral $ t .&. 0xff)
in fromIntegral (((a + b) `xor` c) + d) `shiftL` 32
makeKeySchedule :: [Word32] -> Context
makeKeySchedule key =
let v = unsafeDoIO $ do
mv <- createKeySchedule
forM_ (zip key [0..17]) $ \(k, i) -> mutableArrayWriteXor32 mv i k
prepare mv
mutableArray32Freeze mv
in BF (\i -> arrayRead32 v i)
(\i -> arrayRead32 v (s0+i))
(\i -> arrayRead32 v (s1+i))
(\i -> arrayRead32 v (s2+i))
(\i -> arrayRead32 v (s3+i))
where
s0 = 18
s1 = 274
s2 = 530
s3 = 786
prepare mctx = loop 0 0
where loop i input
| i == 1042 = return ()
| otherwise = do
ninput <- coreCryptoMutable input
let (nl, nr) = w64to32 ninput
mutableArrayWrite32 mctx i nl
mutableArrayWrite32 mctx (i+1) nr
loop (i+2) ninput
coreCryptoMutable :: Word64 -> IO Word64
coreCryptoMutable input = doRound input 0
where doRound i roundIndex
| roundIndex == 16 = do
pVal1 <- mutableArrayRead32 mctx 16
pVal2 <- mutableArrayRead32 mctx 17
let final = (fromIntegral pVal1 `shiftL` 32) .|. fromIntegral pVal2
return $ rotateL (i `xor` final) 32
| otherwise = do
pVal <- mutableArrayRead32 mctx roundIndex
let newr = fromIntegral (i `shiftR` 32) `xor` pVal
newr' <- f newr
let newi = ((i `shiftL` 32) `xor` newr') .|. (fromIntegral newr)
doRound newi (roundIndex+1)
f :: Word32 -> IO Word64
f t = do a <- mutableArrayRead32 mctx (s0 + fromIntegral ((t `shiftR` 24) .&. 0xff))
b <- mutableArrayRead32 mctx (s1 + fromIntegral ((t `shiftR` 16) .&. 0xff))
c <- mutableArrayRead32 mctx (s2 + fromIntegral ((t `shiftR` 8) .&. 0xff))
d <- mutableArrayRead32 mctx (s3 + fromIntegral (t .&. 0xff))
return (fromIntegral (((a + b) `xor` c) + d) `shiftL` 32)

28
Crypto/Cipher/Camellia.hs Normal file
View File

@ -0,0 +1,28 @@
-- |
-- Module : Crypto.Cipher.Camellia
-- License : BSD-style
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
-- Stability : experimental
-- Portability : Good
--
-- Camellia support. only 128 bit variant available for now.
module Crypto.Cipher.Camellia
( Camellia128
) where
import Crypto.Cipher.Camellia.Primitive
import Crypto.Cipher.Types
-- | Camellia block cipher with 128 bit key
newtype Camellia128 = Camellia128 Camellia
instance Cipher Camellia128 where
cipherName _ = "Camellia128"
cipherKeySize _ = KeySizeFixed 16
cipherInit k = Camellia128 `fmap` initCamellia k
instance BlockCipher Camellia128 where
blockSize _ = 16
ecbEncrypt (Camellia128 key) = encrypt key
ecbDecrypt (Camellia128 key) = decrypt key

View File

@ -0,0 +1,284 @@
-- |
-- Module : Crypto.Cipher.Camellia.Primitive
-- License : BSD-style
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
-- Stability : experimental
-- Portability : Good
--
-- this only cover Camellia 128 bits for now, API will change once
-- 192 and 256 mode are implemented too
{-# LANGUAGE MagicHash #-}
module Crypto.Cipher.Camellia.Primitive
( Camellia
, initCamellia
, encrypt
, decrypt
) where
import Data.Word
import Data.Bits
import qualified Data.ByteString as B
import qualified Data.ByteString.Unsafe as B
import Crypto.Error
import Crypto.Internal.ByteArray
import Crypto.Internal.Words
import Crypto.Internal.WordArray
data Mode = Decrypt | Encrypt
w64tow128 :: (Word64, Word64) -> Word128
w64tow128 (x1, x2) = Word128 x1 x2
w64tow8 :: Word64 -> (Word8, Word8, Word8, Word8, Word8, Word8, Word8, Word8)
w64tow8 x = (t1, t2, t3, t4, t5, t6, t7, t8)
where
t1 = fromIntegral (x `shiftR` 56)
t2 = fromIntegral (x `shiftR` 48)
t3 = fromIntegral (x `shiftR` 40)
t4 = fromIntegral (x `shiftR` 32)
t5 = fromIntegral (x `shiftR` 24)
t6 = fromIntegral (x `shiftR` 16)
t7 = fromIntegral (x `shiftR` 8)
t8 = fromIntegral (x)
w8tow64 :: B.ByteString -> Word64
w8tow64 b = (sh t1 56 .|. sh t2 48 .|. sh t3 40 .|. sh t4 32 .|. sh t5 24 .|. sh t6 16 .|. sh t7 8 .|. sh t8 0)
where
t1 = B.unsafeIndex b 0
t2 = B.unsafeIndex b 1
t3 = B.unsafeIndex b 2
t4 = B.unsafeIndex b 3
t5 = B.unsafeIndex b 4
t6 = B.unsafeIndex b 5
t7 = B.unsafeIndex b 6
t8 = B.unsafeIndex b 7
sh i r = (fromIntegral i) `shiftL` r
sbox :: Int -> Word8
sbox = arrayRead8 t
where t = array8
"\x70\x82\x2c\xec\xb3\x27\xc0\xe5\xe4\x85\x57\x35\xea\x0c\xae\x41\
\\x23\xef\x6b\x93\x45\x19\xa5\x21\xed\x0e\x4f\x4e\x1d\x65\x92\xbd\
\\x86\xb8\xaf\x8f\x7c\xeb\x1f\xce\x3e\x30\xdc\x5f\x5e\xc5\x0b\x1a\
\\xa6\xe1\x39\xca\xd5\x47\x5d\x3d\xd9\x01\x5a\xd6\x51\x56\x6c\x4d\
\\x8b\x0d\x9a\x66\xfb\xcc\xb0\x2d\x74\x12\x2b\x20\xf0\xb1\x84\x99\
\\xdf\x4c\xcb\xc2\x34\x7e\x76\x05\x6d\xb7\xa9\x31\xd1\x17\x04\xd7\
\\x14\x58\x3a\x61\xde\x1b\x11\x1c\x32\x0f\x9c\x16\x53\x18\xf2\x22\
\\xfe\x44\xcf\xb2\xc3\xb5\x7a\x91\x24\x08\xe8\xa8\x60\xfc\x69\x50\
\\xaa\xd0\xa0\x7d\xa1\x89\x62\x97\x54\x5b\x1e\x95\xe0\xff\x64\xd2\
\\x10\xc4\x00\x48\xa3\xf7\x75\xdb\x8a\x03\xe6\xda\x09\x3f\xdd\x94\
\\x87\x5c\x83\x02\xcd\x4a\x90\x33\x73\x67\xf6\xf3\x9d\x7f\xbf\xe2\
\\x52\x9b\xd8\x26\xc8\x37\xc6\x3b\x81\x96\x6f\x4b\x13\xbe\x63\x2e\
\\xe9\x79\xa7\x8c\x9f\x6e\xbc\x8e\x29\xf5\xf9\xb6\x2f\xfd\xb4\x59\
\\x78\x98\x06\x6a\xe7\x46\x71\xba\xd4\x25\xab\x42\x88\xa2\x8d\xfa\
\\x72\x07\xb9\x55\xf8\xee\xac\x0a\x36\x49\x2a\x68\x3c\x38\xf1\xa4\
\\x40\x28\xd3\x7b\xbb\xc9\x43\xc1\x15\xe3\xad\xf4\x77\xc7\x80\x9e"#
sbox1 :: Word8 -> Word8
sbox1 x = sbox (fromIntegral x)
sbox2 :: Word8 -> Word8
sbox2 x = sbox1 x `rotateL` 1
sbox3 :: Word8 -> Word8
sbox3 x = sbox1 x `rotateL` 7
sbox4 :: Word8 -> Word8
sbox4 x = sbox1 (x `rotateL` 1)
sigma1, sigma2, sigma3, sigma4, sigma5, sigma6 :: Word64
sigma1 = 0xA09E667F3BCC908B
sigma2 = 0xB67AE8584CAA73B2
sigma3 = 0xC6EF372FE94F82BE
sigma4 = 0x54FF53A5F1D36F1C
sigma5 = 0x10E527FADE682D1D
sigma6 = 0xB05688C2B3E6C1FD
rotl128 :: Word128 -> Int -> Word128
rotl128 v 0 = v
rotl128 (Word128 x1 x2) 64 = Word128 x2 x1
rotl128 v@(Word128 x1 x2) w
| w > 64 = (v `rotl128` 64) `rotl128` (w - 64)
| otherwise = Word128 (x1high .|. x2low) (x2high .|. x1low)
where
splitBits i = (i .&. complement x, i .&. x)
where x = 2 ^ w - 1
(x1high, x1low) = splitBits (x1 `rotateL` w)
(x2high, x2low) = splitBits (x2 `rotateL` w)
data Camellia = Camellia
{ k :: Array64
, kw :: Array64
, ke :: Array64
}
setKeyInterim :: ByteArray key => key -> (Word128, Word128, Word128, Word128)
setKeyInterim keyseed = (w64tow128 kL, w64tow128 kR, w64tow128 kA, w64tow128 kB)
where kL = (byteArrayToW64BE keyseed 0, byteArrayToW64BE keyseed 8)
kR = (0, 0)
kA = let d1 = (fst kL `xor` fst kR)
d2 = (snd kL `xor` snd kR)
d3 = d2 `xor` feistel d1 sigma1
d4 = d1 `xor` feistel d3 sigma2
d5 = d4 `xor` (fst kL)
d6 = d3 `xor` (snd kL)
d7 = d6 `xor` feistel d5 sigma3
d8 = d5 `xor` feistel d7 sigma4
in (d8, d7)
kB = let d1 = (fst kA `xor` fst kR)
d2 = (snd kA `xor` snd kR)
d3 = d2 `xor` feistel d1 sigma5
d4 = d1 `xor` feistel d3 sigma6
in (d4, d3)
-- | Initialize a 128-bit key
-- Return the initialized key or a error message if the given
-- keyseed was not 16-bytes in length.
--
initCamellia :: ByteArray key
=> key -- ^ The key to create the camellia context
-> CryptoFailable Camellia
initCamellia key
| byteArrayLength key /= 16 = CryptoFailed $ CryptoError_KeySizeInvalid
| otherwise =
let (kL, _, kA, _) = setKeyInterim key in
let (Word128 kw1 kw2) = (kL `rotl128` 0) in
let (Word128 k1 k2) = (kA `rotl128` 0) in
let (Word128 k3 k4) = (kL `rotl128` 15) in
let (Word128 k5 k6) = (kA `rotl128` 15) in
let (Word128 ke1 ke2) = (kA `rotl128` 30) in --ke1 = (KA <<< 30) >> 64; ke2 = (KA <<< 30) & MASK64;
let (Word128 k7 k8) = (kL `rotl128` 45) in --k7 = (KL <<< 45) >> 64; k8 = (KL <<< 45) & MASK64;
let (Word128 k9 _) = (kA `rotl128` 45) in --k9 = (KA <<< 45) >> 64;
let (Word128 _ k10) = (kL `rotl128` 60) in
let (Word128 k11 k12) = (kA `rotl128` 60) in
let (Word128 ke3 ke4) = (kL `rotl128` 77) in
let (Word128 k13 k14) = (kL `rotl128` 94) in
let (Word128 k15 k16) = (kA `rotl128` 94) in
let (Word128 k17 k18) = (kL `rotl128` 111) in
let (Word128 kw3 kw4) = (kA `rotl128` 111) in
CryptoPassed $ Camellia
{ kw = array64 4 [ kw1, kw2, kw3, kw4 ]
, ke = array64 4 [ ke1, ke2, ke3, ke4 ]
, k = array64 18 [ k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13, k14, k15, k16, k17, k18 ]
}
feistel :: Word64 -> Word64 -> Word64
feistel fin sk =
let x = fin `xor` sk in
let (t1, t2, t3, t4, t5, t6, t7, t8) = w64tow8 x in
let t1' = sbox1 t1 in
let t2' = sbox2 t2 in
let t3' = sbox3 t3 in
let t4' = sbox4 t4 in
let t5' = sbox2 t5 in
let t6' = sbox3 t6 in
let t7' = sbox4 t7 in
let t8' = sbox1 t8 in
let y1 = t1' `xor` t3' `xor` t4' `xor` t6' `xor` t7' `xor` t8' in
let y2 = t1' `xor` t2' `xor` t4' `xor` t5' `xor` t7' `xor` t8' in
let y3 = t1' `xor` t2' `xor` t3' `xor` t5' `xor` t6' `xor` t8' in
let y4 = t2' `xor` t3' `xor` t4' `xor` t5' `xor` t6' `xor` t7' in
let y5 = t1' `xor` t2' `xor` t6' `xor` t7' `xor` t8' in
let y6 = t2' `xor` t3' `xor` t5' `xor` t7' `xor` t8' in
let y7 = t3' `xor` t4' `xor` t5' `xor` t6' `xor` t8' in
let y8 = t1' `xor` t4' `xor` t5' `xor` t6' `xor` t7' in
w8tow64 $ B.pack [y1, y2, y3, y4, y5, y6, y7, y8]
fl :: Word64 -> Word64 -> Word64
fl fin sk =
let (x1, x2) = w64to32 fin in
let (k1, k2) = w64to32 sk in
let y2 = x2 `xor` ((x1 .&. k1) `rotateL` 1) in
let y1 = x1 `xor` (y2 .|. k2) in
w32to64 (y1, y2)
flinv :: Word64 -> Word64 -> Word64
flinv fin sk =
let (y1, y2) = w64to32 fin in
let (k1, k2) = w64to32 sk in
let x1 = y1 `xor` (y2 .|. k2) in
let x2 = y2 `xor` ((x1 .&. k1) `rotateL` 1) in
w32to64 (x1, x2)
{- in decrypt mode 0->17 1->16 ... -}
getKeyK :: Mode -> Camellia -> Int -> Word64
getKeyK Encrypt key i = k key `arrayRead64` i
getKeyK Decrypt key i = k key `arrayRead64` (17 - i)
{- in decrypt mode 0->3 1->2 2->1 3->0 -}
getKeyKe :: Mode -> Camellia -> Int -> Word64
getKeyKe Encrypt key i = ke key `arrayRead64` i
getKeyKe Decrypt key i = ke key `arrayRead64` (3 - i)
{- in decrypt mode 0->2 1->3 2->0 3->1 -}
getKeyKw :: Mode -> Camellia -> Int -> Word64
getKeyKw Encrypt key i = (kw key) `arrayRead64` i
getKeyKw Decrypt key i = (kw key) `arrayRead64` ((i + 2) `mod` 4)
{- perform the following
D2 = D2 ^ F(D1, k1); // Round 1
D1 = D1 ^ F(D2, k2); // Round 2
D2 = D2 ^ F(D1, k3); // Round 3
D1 = D1 ^ F(D2, k4); // Round 4
D2 = D2 ^ F(D1, k5); // Round 5
D1 = D1 ^ F(D2, k6); // Round 6
-}
doBlockRound :: Mode -> Camellia -> Word64 -> Word64 -> Int -> (Word64, Word64)
doBlockRound mode key d1 d2 i =
let r1 = d2 `xor` feistel d1 (getKeyK mode key (0+i)) in {- Round 1+i -}
let r2 = d1 `xor` feistel r1 (getKeyK mode key (1+i)) in {- Round 2+i -}
let r3 = r1 `xor` feistel r2 (getKeyK mode key (2+i)) in {- Round 3+i -}
let r4 = r2 `xor` feistel r3 (getKeyK mode key (3+i)) in {- Round 4+i -}
let r5 = r3 `xor` feistel r4 (getKeyK mode key (4+i)) in {- Round 5+i -}
let r6 = r4 `xor` feistel r5 (getKeyK mode key (5+i)) in {- Round 6+i -}
(r6, r5)
doBlock :: Mode -> Camellia -> Word128 -> Word128
doBlock mode key (Word128 d1 d2) =
let d1a = d1 `xor` (getKeyKw mode key 0) in {- Prewhitening -}
let d2a = d2 `xor` (getKeyKw mode key 1) in
let (d1b, d2b) = doBlockRound mode key d1a d2a 0 in
let d1c = fl d1b (getKeyKe mode key 0) in {- FL -}
let d2c = flinv d2b (getKeyKe mode key 1) in {- FLINV -}
let (d1d, d2d) = doBlockRound mode key d1c d2c 6 in
let d1e = fl d1d (getKeyKe mode key 2) in {- FL -}
let d2e = flinv d2d (getKeyKe mode key 3) in {- FLINV -}
let (d1f, d2f) = doBlockRound mode key d1e d2e 12 in
let d2g = d2f `xor` (getKeyKw mode key 2) in {- Postwhitening -}
let d1g = d1f `xor` (getKeyKw mode key 3) in
w64tow128 (d2g, d1g)
{- encryption for 128 bits blocks -}
encryptBlock :: Camellia -> Word128 -> Word128
encryptBlock = doBlock Encrypt
{- decryption for 128 bits blocks -}
decryptBlock :: Camellia -> Word128 -> Word128
decryptBlock = doBlock Decrypt
-- | Encrypts the given ByteString using the given Key
encrypt :: ByteArray ba
=> Camellia -- ^ The key to use
-> ba -- ^ The data to encrypt
-> ba
encrypt key = byteArrayMapAsWord128 (encryptBlock key)
-- | Decrypts the given ByteString using the given Key
decrypt :: ByteArray ba
=> Camellia -- ^ The key to use
-> ba -- ^ The data to decrypt
-> ba
decrypt key = byteArrayMapAsWord128 (decryptBlock key)

37
Crypto/Cipher/DES.hs Normal file
View File

@ -0,0 +1,37 @@
-- |
-- Module : Crypto.Cipher.DES
-- License : BSD-style
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
-- Stability : stable
-- Portability : good
--
module Crypto.Cipher.DES
( DES
) where
import Data.Word
import Crypto.Error
import Crypto.Cipher.Types
import Crypto.Cipher.DES.Primitive
import Crypto.Internal.ByteArray
-- | DES Context
data DES = DES Word64
deriving (Eq)
instance Cipher DES where
cipherName _ = "DES"
cipherKeySize _ = KeySizeFixed 8
cipherInit k = initDES k
instance BlockCipher DES where
blockSize _ = 8
ecbEncrypt (DES key) = byteArrayMapAsWord64 (unBlock . encrypt key . Block)
ecbDecrypt (DES key) = byteArrayMapAsWord64 (unBlock . decrypt key . Block)
initDES :: ByteArray key => key -> CryptoFailable DES
initDES k
| len == 8 = CryptoPassed $ DES key
| otherwise = CryptoFailed $ CryptoError_KeySizeInvalid
where len = byteArrayLength k
key = byteArrayToW64BE k 0

View File

@ -0,0 +1,220 @@
{-# LANGUAGE FlexibleInstances #-}
-----------------------------------------------------------------------------
-- |
-- Module : Crypto.Cipher.DES.Primitive
-- License : BSD-style
--
-- This module is copy of DES module from Crypto package.
-- http://hackage.haskell.org/package/Crypto
--
-----------------------------------------------------------------------------
module Crypto.Cipher.DES.Primitive (encrypt, decrypt, Block(..)) where
import Data.Word
import Data.Bits
newtype Block = Block { unBlock :: Word64 }
type Rotation = Int
type Key = Word64
type Bits4 = [Bool]
type Bits6 = [Bool]
type Bits32 = [Bool]
type Bits48 = [Bool]
type Bits56 = [Bool]
type Bits64 = [Bool]
desXor :: [Bool] -> [Bool] -> [Bool]
desXor a b = zipWith xor a b
desRotate :: [Bool] -> Int -> [Bool]
desRotate bits rot = drop rot' bits ++ take rot' bits
where rot' = rot `mod` length bits
bitify :: Word64 -> Bits64
bitify w = map (\b -> w .&. (shiftL 1 b) /= 0) [63,62..0]
unbitify :: Bits64 -> Word64
unbitify bs = foldl (\i b -> if b then 1 + shiftL i 1 else shiftL i 1) 0 bs
initial_permutation :: Bits64 -> Bits64
initial_permutation mb = map ((!!) mb) i
where i = [57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3,
61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7,
56, 48, 40, 32, 24, 16, 8, 0, 58, 50, 42, 34, 26, 18, 10, 2,
60, 52, 44, 36, 28, 20, 12, 4, 62, 54, 46, 38, 30, 22, 14, 6]
{-
"\x39\x31\x29\x21\x19\x11\x09\x01\x3b\x33\x2b\x23\x1b\x13\
\\x0b\x03\x3d\x35\x2d\x25\x1d\x15\x0d\x05\x3f\x37\x2f\x27\
\\x1f\x17\x0f\x07\x38\x30\x28\x20\x18\x10\x08\x00\x3a\x32\
\\x2a\x22\x1a\x12\x0a\x02\x3c\x34\x2c\x24\x1c\x14\x0c\x04\
\\x3e\x36\x2e\x26\x1e\x16\x0e\x06"
-}
key_transformation :: Bits64 -> Bits56
key_transformation kb = map ((!!) kb) i
where i = [56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17,
9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35,
62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21,
13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3]
{-
"\x38\x30\x28\x20\x18\x10\x08\x00\x39\x31\x29\x21\x19\x11\
\\x09\x01\x3a\x32\x2a\x22\x1a\x12\x0a\x02\x3b\x33\x2b\x23\
\\x3e\x36\x2e\x26\x1e\x16\x0e\x06\x3d\x35\x2d\x25\x1d\x15\
\\x0d\x05\x3c\x34\x2c\x24\x1c\x14\x0c\x04\x1b\x13\x0b\x03"
-}
des_enc :: Block -> Key -> Block
des_enc = do_des [1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28]
des_dec :: Block -> Key -> Block
des_dec = do_des [28,27,25,23,21,19,17,15,14,12,10,8,6,4,2,1]
do_des :: [Rotation] -> Block -> Key -> Block
do_des rots (Block m) k = Block $ des_work rots (takeDrop 32 mb) kb
where kb = key_transformation $ bitify k
mb = initial_permutation $ bitify m
des_work :: [Rotation] -> (Bits32, Bits32) -> Bits56 -> Word64
des_work [] (ml, mr) _ = unbitify $ final_perm $ (mr ++ ml)
des_work (r:rs) mb kb = des_work rs mb' kb
where mb' = do_round r mb kb
do_round :: Rotation -> (Bits32, Bits32) -> Bits56 -> (Bits32, Bits32)
do_round r (ml, mr) kb = (mr, m')
where kb' = get_key kb r
comp_kb = compression_permutation kb'
expa_mr = expansion_permutation mr
res = comp_kb `desXor` expa_mr
res' = tail $ iterate (trans 6) ([], res)
trans n (_, b) = (take n b, drop n b)
res_s = concat $ zipWith (\f (x,_) -> f x) [s_box_1, s_box_2,
s_box_3, s_box_4,
s_box_5, s_box_6,
s_box_7, s_box_8] res'
res_p = p_box res_s
m' = res_p `desXor` ml
get_key :: Bits56 -> Rotation -> Bits56
get_key kb r = kb'
where (kl, kr) = takeDrop 28 kb
kb' = desRotate kl r ++ desRotate kr r
compression_permutation :: Bits56 -> Bits48
compression_permutation kb = map ((!!) kb) i
where i = [13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9,
22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1,
40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,
43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31]
expansion_permutation :: Bits32 -> Bits48
expansion_permutation mb = map ((!!) mb) i
where i = [31, 0, 1, 2, 3, 4, 3, 4, 5, 6, 7, 8,
7, 8, 9, 10, 11, 12, 11, 12, 13, 14, 15, 16,
15, 16, 17, 18, 19, 20, 19, 20, 21, 22, 23, 24,
23, 24, 25, 26, 27, 28, 27, 28, 29, 30, 31, 0]
s_box :: [[Word8]] -> Bits6 -> Bits4
s_box s [a,b,c,d,e,f] = to_bool 4 $ (s !! row) !! col
where row = sum $ zipWith numericise [a,f] [1, 0]
col = sum $ zipWith numericise [b,c,d,e] [3, 2, 1, 0]
numericise :: Bool -> Int -> Int
numericise = (\x y -> if x then 2^y else 0)
to_bool :: Int -> Word8 -> [Bool]
to_bool 0 _ = []
to_bool n i = ((i .&. 8) == 8):to_bool (n-1) (shiftL i 1)
s_box _ _ = error "DES: internal error bits6 more than 6 elements"
s_box_1 :: Bits6 -> Bits4
s_box_1 = s_box i
where i = [[14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7],
[ 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8],
[ 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0],
[15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13]]
s_box_2 :: Bits6 -> Bits4
s_box_2 = s_box i
where i = [[15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10],
[3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5],
[0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15],
[13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9]]
s_box_3 :: Bits6 -> Bits4
s_box_3 = s_box i
where i = [[10, 0, 9, 14 , 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8],
[13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1],
[13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7],
[1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12]]
s_box_4 :: Bits6 -> Bits4
s_box_4 = s_box i
where i = [[7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15],
[13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9],
[10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4],
[3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14]]
s_box_5 :: Bits6 -> Bits4
s_box_5 = s_box i
where i = [[2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9],
[14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6],
[4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14],
[11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3]]
s_box_6 :: Bits6 -> Bits4
s_box_6 = s_box i
where i = [[12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11],
[10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8],
[9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6],
[4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13]]
s_box_7 :: Bits6 -> Bits4
s_box_7 = s_box i
where i = [[4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1],
[13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6],
[1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2],
[6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12]]
s_box_8 :: Bits6 -> Bits4
s_box_8 = s_box i
where i = [[13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7],
[1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2],
[7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8],
[2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11]]
p_box :: Bits32 -> Bits32
p_box kb = map ((!!) kb) i
where i = [15, 6, 19, 20, 28, 11, 27, 16, 0, 14, 22, 25, 4, 17, 30, 9,
1, 7, 23, 13, 31, 26, 2, 8, 18, 12, 29, 5, 21, 10, 3, 24]
final_perm :: Bits64 -> Bits64
final_perm kb = map ((!!) kb) i
where i = [39, 7, 47, 15, 55, 23, 63, 31, 38, 6, 46, 14, 54, 22, 62, 30,
37, 5, 45, 13, 53, 21, 61, 29, 36, 4, 44, 12, 52, 20, 60, 28,
35, 3, 43, 11, 51, 19, 59, 27, 34, 2, 42, 10, 50, 18, 58, 26,
33, 1, 41, 9, 49, 17, 57, 25, 32, 0, 40 , 8, 48, 16, 56, 24]
takeDrop :: Int -> [a] -> ([a], [a])
takeDrop _ [] = ([], [])
takeDrop 0 xs = ([], xs)
takeDrop n (x:xs) = (x:ys, zs)
where (ys, zs) = takeDrop (n-1) xs
-- | Basic DES encryption which takes a key and a block of plaintext
-- and returns the encrypted block of ciphertext according to the standard.
encrypt :: Word64 -> Block -> Block
encrypt = flip des_enc
-- | Basic DES decryption which takes a key and a block of ciphertext and
-- returns the decrypted block of plaintext according to the standard.
decrypt :: Word64 -> Block -> Block
decrypt = flip des_dec

View File

@ -0,0 +1,25 @@
-- |
-- Module : Crypto.Cipher.DES.Serialization
-- License : BSD-style
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
-- Stability : stable
-- Portability : good
--
-- basic routine to convert between W64 and bytestring for DES.
--
module Crypto.Cipher.DES.Serialization
( toBS
) where
import qualified Data.ByteString as B
import Crypto.Cipher.DES.Primitive (Block(..))
import Crypto.Internal.ByteArray
import Crypto.Internal.Endian
import Data.Word (Word64)
import Foreign.Storable
import Foreign.Ptr (castPtr, plusPtr, Ptr)
toBS :: Block -> B.ByteString
toBS (Block w) = byteArrayAllocAndFreeze 8 $ \ptr -> poke ptr (toBE64 w)

View File

@ -0,0 +1,88 @@
-- |
-- Module : Crypto.Cipher.TripleDES
-- License : BSD-style
-- Stability : experimental
-- Portability : ???
module Crypto.Cipher.TripleDES
( DES_EEE3
, DES_EDE3
, DES_EEE2
, DES_EDE2
) where
import Data.Word
import Crypto.Error
import Crypto.Cipher.Types
import Crypto.Cipher.DES.Primitive
import Crypto.Internal.ByteArray
-- | 3DES with 3 different keys used all in the same direction
data DES_EEE3 = DES_EEE3 Word64 Word64 Word64
deriving (Eq)
-- | 3DES with 3 different keys used in alternative direction
data DES_EDE3 = DES_EDE3 Word64 Word64 Word64
deriving (Eq)
-- | 3DES where the first and third keys are equal, used in the same direction
data DES_EEE2 = DES_EEE2 Word64 Word64 -- key1 and key3 are equal
deriving (Eq)
-- | 3DES where the first and third keys are equal, used in alternative direction
data DES_EDE2 = DES_EDE2 Word64 Word64 -- key1 and key3 are equal
deriving (Eq)
instance Cipher DES_EEE3 where
cipherName _ = "3DES_EEE"
cipherKeySize _ = KeySizeFixed 24
cipherInit k = init3DES DES_EEE3 k
instance Cipher DES_EDE3 where
cipherName _ = "3DES_EDE"
cipherKeySize _ = KeySizeFixed 24
cipherInit k = init3DES DES_EDE3 k
instance Cipher DES_EDE2 where
cipherName _ = "2DES_EDE"
cipherKeySize _ = KeySizeFixed 16
cipherInit k = init2DES DES_EDE2 k
instance Cipher DES_EEE2 where
cipherName _ = "2DES_EEE"
cipherKeySize _ = KeySizeFixed 16
cipherInit k = init2DES DES_EEE2 k
instance BlockCipher DES_EEE3 where
blockSize _ = 8
ecbEncrypt (DES_EEE3 k1 k2 k3) = byteArrayMapAsWord64 (unBlock . (encrypt k3 . encrypt k2 . encrypt k1) . Block)
ecbDecrypt (DES_EEE3 k1 k2 k3) = byteArrayMapAsWord64 (unBlock . (decrypt k1 . decrypt k2 . decrypt k3) . Block)
instance BlockCipher DES_EDE3 where
blockSize _ = 8
ecbEncrypt (DES_EDE3 k1 k2 k3) = byteArrayMapAsWord64 (unBlock . (encrypt k3 . decrypt k2 . encrypt k1) . Block)
ecbDecrypt (DES_EDE3 k1 k2 k3) = byteArrayMapAsWord64 (unBlock . (decrypt k1 . encrypt k2 . decrypt k3) . Block)
instance BlockCipher DES_EEE2 where
blockSize _ = 8
ecbEncrypt (DES_EEE2 k1 k2) = byteArrayMapAsWord64 (unBlock . (encrypt k1 . encrypt k2 . encrypt k1) . Block)
ecbDecrypt (DES_EEE2 k1 k2) = byteArrayMapAsWord64 (unBlock . (decrypt k1 . decrypt k2 . decrypt k1) . Block)
instance BlockCipher DES_EDE2 where
blockSize _ = 8
ecbEncrypt (DES_EDE2 k1 k2) = byteArrayMapAsWord64 (unBlock . (encrypt k1 . decrypt k2 . encrypt k1) . Block)
ecbDecrypt (DES_EDE2 k1 k2) = byteArrayMapAsWord64 (unBlock . (decrypt k1 . encrypt k2 . decrypt k1) . Block)
init3DES :: ByteArray key => (Word64 -> Word64 -> Word64 -> a) -> key -> CryptoFailable a
init3DES constr k
| len == 24 = CryptoPassed $ constr k1 k2 k3
| otherwise = CryptoFailed CryptoError_KeySizeInvalid
where len = byteArrayLength k
(k1, k2, k3) = (byteArrayToW64BE k 0, byteArrayToW64BE k 8, byteArrayToW64BE k 16)
init2DES :: ByteArray key => (Word64 -> Word64 -> a) -> key -> CryptoFailable a
init2DES constr k
| len == 16 = CryptoPassed $ constr k1 k2
| otherwise = CryptoFailed CryptoError_KeySizeInvalid
where len = byteArrayLength k
(k1, k2) = (byteArrayToW64BE k 0, byteArrayToW64BE k 8)

View File

@ -1,3 +1,41 @@
-- |
-- Module : Crypto.Cipher.Types
-- License : BSD-style
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
-- Stability : Stable
-- Portability : Excellent
--
-- symmetric cipher basic types
--
{-# LANGUAGE DeriveDataTypeable #-}
module Crypto.Cipher.Types module Crypto.Cipher.Types
( (
-- * Cipher classes
Cipher(..)
, BlockCipher(..)
, ecbEncryptLegacy
, ecbDecryptLegacy
, StreamCipher(..)
, DataUnitOffset
, KeySizeSpecifier(..)
, AEAD(..)
, AEADState(..)
, AEADMode(..)
, AEADModeImpl(..)
-- , cfb8Encrypt
-- , cfb8Decrypt
-- * AEAD functions
, module Crypto.Cipher.Types.AEAD
-- * Initial Vector type and constructor
, IV
, makeIV
, nullIV
, ivAdd
-- * Authentification Tag
, AuthTag(..)
) where ) where
import Crypto.Cipher.Types.Base
import Crypto.Cipher.Types.Block
import Crypto.Cipher.Types.Stream
import Crypto.Cipher.Types.AEAD

View File

@ -0,0 +1,63 @@
-- |
-- Module : Crypto.Cipher.Types.AEAD
-- License : BSD-style
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
-- Stability : Stable
-- Portability : Excellent
--
-- AEAD cipher basic types
--
module Crypto.Cipher.Types.AEAD where
import Data.ByteString (ByteString)
import qualified Data.ByteString as B
import Crypto.Cipher.Types.Base
import Crypto.Cipher.Types.Block
import Crypto.Internal.ByteArray
-- | Append associated data into the AEAD state
aeadAppendHeader :: BlockCipher a => AEAD a -> ByteString -> AEAD a
aeadAppendHeader (AEAD cipher (AEADState state)) bs =
AEAD cipher $ AEADState (aeadStateAppendHeader cipher state bs)
-- | Encrypt input and append into the AEAD state
aeadEncrypt :: BlockCipher a => AEAD a -> ByteString -> (ByteString, AEAD a)
aeadEncrypt (AEAD cipher (AEADState state)) input = (output, AEAD cipher (AEADState nst))
where (output, nst) = aeadStateEncrypt cipher state input
-- | Decrypt input and append into the AEAD state
aeadDecrypt :: BlockCipher a => AEAD a -> ByteString -> (ByteString, AEAD a)
aeadDecrypt (AEAD cipher (AEADState state)) input = (output, AEAD cipher (AEADState nst))
where (output, nst) = aeadStateDecrypt cipher state input
-- | Finalize the AEAD state and create an authentification tag
aeadFinalize :: BlockCipher a => AEAD a -> Int -> AuthTag
aeadFinalize (AEAD cipher (AEADState state)) len =
aeadStateFinalize cipher state len
-- | Simple AEAD encryption
aeadSimpleEncrypt :: BlockCipher a
=> AEAD a -- ^ A new AEAD Context
-> B.ByteString -- ^ Optional Authentified Header
-> B.ByteString -- ^ Optional Plaintext
-> Int -- ^ Tag length
-> (AuthTag, B.ByteString) -- ^ Authentification tag and ciphertext
aeadSimpleEncrypt aeadIni header input taglen = (tag, output)
where aead = aeadAppendHeader aeadIni header
(output, aeadFinal) = aeadEncrypt aead input
tag = aeadFinalize aeadFinal taglen
-- | Simple AEAD decryption
aeadSimpleDecrypt :: BlockCipher a
=> AEAD a -- ^ A new AEAD Context
-> B.ByteString -- ^ Optional Authentified Header
-> B.ByteString -- ^ Optional Plaintext
-> AuthTag -- ^ Tag length
-> Maybe B.ByteString -- ^ Plaintext
aeadSimpleDecrypt aeadIni header input authTag
| tag == authTag = Just output
| otherwise = Nothing
where aead = aeadAppendHeader aeadIni header
(output, aeadFinal) = aeadDecrypt aead input
tag = aeadFinalize aeadFinal (byteArrayLength authTag)

View File

@ -0,0 +1,60 @@
-- |
-- Module : Crypto.Cipher.Types.Base
-- License : BSD-style
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
-- Stability : Stable
-- Portability : Excellent
--
-- symmetric cipher basic types
--
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Crypto.Cipher.Types.Base
( KeySizeSpecifier(..)
, Cipher(..)
, AuthTag(..)
, AEADMode(..)
, DataUnitOffset
) where
import Data.Word
import Data.ByteString (ByteString)
import Crypto.Internal.ByteArray
import Crypto.Error
-- | Different specifier for key size in bytes
data KeySizeSpecifier =
KeySizeRange Int Int -- ^ in the range [min,max]
| KeySizeEnum [Int] -- ^ one of the specified values
| KeySizeFixed Int -- ^ a specific size
deriving (Show,Eq)
-- | Offset inside an XTS data unit, measured in block size.
type DataUnitOffset = Word32
-- | Authentification Tag for AE cipher mode
newtype AuthTag = AuthTag { unAuthTag :: ByteString }
deriving (Show, ByteArrayAccess)
instance Eq AuthTag where
(AuthTag a) == (AuthTag b) = byteArrayConstEq a b
-- | AEAD Mode
data AEADMode =
AEAD_OCB -- OCB3
| AEAD_CCM
| AEAD_EAX
| AEAD_CWC
| AEAD_GCM
deriving (Show,Eq)
-- | Symmetric cipher class.
class Cipher cipher where
-- | Initialize a cipher context from a key
cipherInit :: ByteArray key => key -> CryptoFailable cipher
-- | Cipher name
cipherName :: cipher -> String
-- | return the size of the key required for this cipher.
-- Some cipher accept any size for key
cipherKeySize :: cipher -> KeySizeSpecifier

View File

@ -0,0 +1,299 @@
-- |
-- Module : Crypto.Cipher.Types.Block
-- License : BSD-style
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
-- Stability : Stable
-- Portability : Excellent
--
-- block cipher basic types
--
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE ViewPatterns #-}
module Crypto.Cipher.Types.Block
(
-- * BlockCipher
BlockCipher(..)
, ecbEncryptLegacy
, ecbDecryptLegacy
-- * initialization vector (IV)
, IV(..)
, makeIV
, nullIV
, ivAdd
-- * XTS
, XTS
-- * AEAD
, AEAD(..)
, AEADState(..)
, AEADModeImpl(..)
-- * CFB 8 bits
--, cfb8Encrypt
--, cfb8Decrypt
) where
import Data.ByteString (ByteString)
import qualified Data.ByteString as B
import Data.Byteable
import Data.Word
import Crypto.Cipher.Types.Base
--import Crypto.Cipher.Types.GF
import Crypto.Cipher.Types.Utils
import Crypto.Internal.ByteArray
import Foreign.Ptr
import Foreign.Storable
-- | an IV parametrized by the cipher
data IV c = forall byteArray . ByteArray byteArray => IV byteArray
instance BlockCipher c => ByteArrayAccess (IV c) where
withByteArray (IV z) f = withByteArray z f
byteArrayLength (IV z) = byteArrayLength z
instance Eq (IV c) where
(IV a) == (IV b) = byteArrayEq a b
type XTS cipher = (cipher, cipher)
-> IV cipher -- ^ Usually represent the Data Unit (e.g. disk sector)
-> DataUnitOffset -- ^ Offset in the data unit in number of blocks
-> ByteString -- ^ Data
-> ByteString -- ^ Processed Data
-- | Symmetric block cipher class
class Cipher cipher => BlockCipher cipher where
-- | Return the size of block required for this block cipher
blockSize :: cipher -> Int
-- | Encrypt blocks
--
-- the input string need to be multiple of the block size
ecbEncrypt :: ByteArray ba => cipher -> ba -> ba
-- | Decrypt blocks
--
-- the input string need to be multiple of the block size
ecbDecrypt :: ByteArray ba => cipher -> ba -> ba
-- | encrypt using the CBC mode.
--
-- input need to be a multiple of the blocksize
cbcEncrypt :: ByteArray ba => cipher -> IV cipher -> ba -> ba
cbcEncrypt = cbcEncryptGeneric
-- | decrypt using the CBC mode.
--
-- input need to be a multiple of the blocksize
cbcDecrypt :: ByteArray ba => cipher -> IV cipher -> ba -> ba
cbcDecrypt = cbcDecryptGeneric
-- | encrypt using the CFB mode.
--
-- input need to be a multiple of the blocksize
cfbEncrypt :: ByteArray ba => cipher -> IV cipher -> ba -> ba
cfbEncrypt = cfbEncryptGeneric
-- | decrypt using the CFB mode.
--
-- input need to be a multiple of the blocksize
cfbDecrypt :: ByteArray ba => cipher -> IV cipher -> ba -> ba
cfbDecrypt = cfbDecryptGeneric
-- | combine using the CTR mode.
--
-- CTR mode produce a stream of randomized data that is combined
-- (by XOR operation) with the input stream.
--
-- encryption and decryption are the same operation.
--
-- input can be of any size
ctrCombine :: ByteArray ba => cipher -> IV cipher -> ba -> ba
ctrCombine = ctrCombineGeneric
-- | Initialize a new AEAD State
--
-- When Nothing is returns, it means the mode is not handled.
aeadInit :: Byteable iv => AEADMode -> cipher -> iv -> Maybe (AEAD cipher)
aeadInit _ _ _ = Nothing
ecbEncryptLegacy :: ByteArray ba
=> (cipher -> ByteString -> ByteString)
-> cipher -> ba -> ba
ecbEncryptLegacy f cipher input =
byteArrayFromBS $ f cipher (byteArrayToBS input)
ecbDecryptLegacy :: ByteArray ba
=> (cipher -> ByteString -> ByteString)
-> cipher -> ba -> ba
ecbDecryptLegacy f cipher input =
byteArrayFromBS $ f cipher (byteArrayToBS input)
-- | class of block cipher with a 128 bits block size
class BlockCipher cipher => BlockCipher128 cipher where
-- | encrypt using the XTS mode.
--
-- input need to be a multiple of the blocksize, and the cipher
-- need to process 128 bits block only
xtsEncrypt :: (cipher, cipher)
-> IV cipher -- ^ Usually represent the Data Unit (e.g. disk sector)
-> DataUnitOffset -- ^ Offset in the data unit in number of blocks
-> ByteString -- ^ Plaintext
-> ByteString -- ^ Ciphertext
xtsEncrypt = undefined -- xtsEncryptGeneric
-- | decrypt using the XTS mode.
--
-- input need to be a multiple of the blocksize, and the cipher
-- need to process 128 bits block only
xtsDecrypt :: (cipher, cipher)
-> IV cipher -- ^ Usually represent the Data Unit (e.g. disk sector)
-> DataUnitOffset -- ^ Offset in the data unit in number of blocks
-> ByteString -- ^ Ciphertext
-> ByteString -- ^ Plaintext
xtsDecrypt = undefined -- xtsDecryptGeneric
-- | Authenticated Encryption with Associated Data algorithms
data AEAD cipher = AEAD cipher (AEADState cipher)
-- | Wrapper for any AEADState
data AEADState cipher = forall st . AEADModeImpl cipher st => AEADState st
-- | Class of AEAD Mode implementation
class BlockCipher cipher => AEADModeImpl cipher state where
aeadStateAppendHeader :: cipher -> state -> ByteString -> state
aeadStateEncrypt :: cipher -> state -> ByteString -> (ByteString, state)
aeadStateDecrypt :: cipher -> state -> ByteString -> (ByteString, state)
aeadStateFinalize :: cipher -> state -> Int -> AuthTag
-- | Create an IV for a specified block cipher
makeIV :: (Byteable b, BlockCipher c) => b -> Maybe (IV c)
makeIV b = toIV undefined
where toIV :: BlockCipher c => c -> Maybe (IV c)
toIV cipher
| byteableLength b == sz = Just (IV $ toBytes b)
| otherwise = Nothing
where sz = blockSize cipher
-- | Create an IV that is effectively representing the number 0
nullIV :: BlockCipher c => IV c
nullIV = toIV undefined
where toIV :: BlockCipher c => c -> IV c
toIV cipher = IV $ B.replicate (blockSize cipher) 0
-- | Increment an IV by a number.
--
-- Assume the IV is in Big Endian format.
ivAdd :: BlockCipher c => IV c -> Int -> IV c
ivAdd (IV b) i = IV $ copy b
where copy :: ByteArray bs => bs -> bs
copy bs = byteArrayCopyAndFreeze bs $ \p -> do
let until0 accu = do
r <- loop accu (byteArrayLength bs - 1) p
case r of
0 -> return ()
_ -> until0 r
until0 i
loop :: Int -> Int -> Ptr Word8 -> IO Int
loop 0 _ _ = return 0
loop acc ofs p = do
v <- peek (p `plusPtr` ofs) :: IO Word8
let accv = acc + fromIntegral v
(hi,lo) = accv `divMod` 256
poke (p `plusPtr` ofs) (fromIntegral lo :: Word8)
if ofs == 0
then return hi
else loop hi (ofs - 1) p
cbcEncryptGeneric :: (ByteArray ba, BlockCipher cipher) => cipher -> IV cipher -> ba -> ba
cbcEncryptGeneric cipher ivini input = byteArrayConcat $ doEnc ivini $ chunk (blockSize cipher) input
where doEnc _ [] = []
doEnc iv (i:is) =
let o = ecbEncrypt cipher $ byteArrayXor iv i
in o : doEnc (IV o) is
cbcDecryptGeneric :: (ByteArray ba, BlockCipher cipher) => cipher -> IV cipher -> ba -> ba
cbcDecryptGeneric cipher ivini input = byteArrayConcat $ doDec ivini $ chunk (blockSize cipher) input
where
doDec _ [] = []
doDec iv (i:is) =
let o = byteArrayXor iv $ ecbDecrypt cipher i
in o : doDec (IV i) is
cfbEncryptGeneric :: (ByteArray ba, BlockCipher cipher) => cipher -> IV cipher -> ba -> ba
cfbEncryptGeneric cipher ivini input = byteArrayConcat $ doEnc ivini $ chunk (blockSize cipher) input
where
doEnc _ [] = []
doEnc (IV iv) (i:is) =
let o = byteArrayXor i $ ecbEncrypt cipher iv
in o : doEnc (IV o) is
cfbDecryptGeneric :: (ByteArray ba, BlockCipher cipher) => cipher -> IV cipher -> ba -> ba
cfbDecryptGeneric cipher ivini input = byteArrayConcat $ doDec ivini $ chunk (blockSize cipher) input
where
doDec _ [] = []
doDec (IV iv) (i:is) =
let o = byteArrayXor i $ ecbEncrypt cipher iv
in o : doDec (IV i) is
ctrCombineGeneric :: (ByteArray ba, BlockCipher cipher) => cipher -> IV cipher -> ba -> ba
ctrCombineGeneric cipher ivini input = byteArrayConcat $ doCnt ivini $ chunk (blockSize cipher) input
where doCnt _ [] = []
doCnt iv@(IV ivd) (i:is) =
let ivEnc = ecbEncrypt cipher ivd
in byteArrayXor i ivEnc : doCnt (ivAdd iv 1) is
{-
xtsEncryptGeneric :: BlockCipher128 cipher => XTS cipher
xtsEncryptGeneric = xtsGeneric ecbEncrypt
xtsDecryptGeneric :: BlockCipher128 cipher => XTS cipher
xtsDecryptGeneric = xtsGeneric ecbDecrypt
xtsGeneric :: BlockCipher128 cipher
=> (cipher -> B.ByteString -> B.ByteString)
-> (cipher, cipher)
-> IV cipher
-> DataUnitOffset
-> ByteString
-> ByteString
xtsGeneric f (cipher, tweakCipher) iv sPoint input
| blockSize cipher /= 16 = error "XTS mode is only available with cipher that have a block size of 128 bits"
| otherwise = byteArrayConcat $ doXts iniTweak $ chunk (blockSize cipher) input
where encTweak = ecbEncrypt tweakCipher iv
iniTweak = iterate xtsGFMul encTweak !! fromIntegral sPoint
doXts _ [] = []
doXts tweak (i:is) =
let o = bxor (f cipher $ bxor i tweak) tweak
in o : doXts (xtsGFMul tweak) is
-}
{-
-- | Encrypt using CFB mode in 8 bit output
--
-- Effectively turn a Block cipher in CFB mode into a Stream cipher
cfb8Encrypt :: BlockCipher a => a -> IV a -> B.ByteString -> B.ByteString
cfb8Encrypt ctx origIv msg = B.unsafeCreate (B.length msg) $ \dst -> loop dst origIv msg
where loop d iv@(IV i) m
| B.null m = return ()
| otherwise = poke d out >> loop (d `plusPtr` 1) ni (B.drop 1 m)
where m' = if B.length m < blockSize ctx
then m `B.append` B.replicate (blockSize ctx - B.length m) 0
else B.take (blockSize ctx) m
r = cfbEncrypt ctx iv m'
out = B.head r
ni = IV (B.drop 1 i `B.snoc` out)
-- | Decrypt using CFB mode in 8 bit output
--
-- Effectively turn a Block cipher in CFB mode into a Stream cipher
cfb8Decrypt :: BlockCipher a => a -> IV a -> B.ByteString -> B.ByteString
cfb8Decrypt ctx origIv msg = B.unsafeCreate (B.length msg) $ \dst -> loop dst origIv msg
where loop d iv@(IV i) m
| B.null m = return ()
| otherwise = poke d out >> loop (d `plusPtr` 1) ni (B.drop 1 m)
where m' = if B.length m < blockSize ctx
then m `B.append` B.replicate (blockSize ctx - B.length m) 0
else B.take (blockSize ctx) m
r = cfbDecrypt ctx iv m'
out = B.head r
ni = IV (B.drop 1 i `B.snoc` B.head m')
-}

49
Crypto/Cipher/Types/GF.hs Normal file
View File

@ -0,0 +1,49 @@
-- |
-- Module : Crypto.Cipher.Types.GF
-- License : BSD-style
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
-- Stability : Stable
-- Portability : Excellent
--
-- Slow Galois Field arithmetic for generic XTS and GCM implementation
--
module Crypto.Cipher.Types.GF
(
-- * XTS support
xtsGFMul
) where
import Control.Applicative
import Data.ByteString (ByteString)
import qualified Data.ByteString as B
import qualified Data.ByteString.Internal as B
import Data.Byteable
import Foreign.Storable
import Foreign.Ptr
import Data.Word
import Data.Bits
-- block size need to be 128 bits.
--
-- FIXME: add support for big endian.
xtsGFMul :: ByteString -> ByteString
xtsGFMul b
| B.length b == 16 = B.unsafeCreate (B.length b) $ \dst ->
withBytePtr b $ \src -> do
(hi,lo) <- gf <$> peek (castPtr src) <*> peek (castPtr src `plusPtr` 8)
poke (castPtr dst) lo
poke (castPtr dst `plusPtr` 8) hi
| otherwise = error "unsupported block size in GF"
where gf :: Word64 -> Word64 -> (Word64, Word64)
gf srcLo srcHi =
((if carryLo then (.|. 1) else id) (srcHi `shiftL` 1)
,(if carryHi then xor 0x87 else id) $ (srcLo `shiftL` 1)
)
where carryHi = srcHi `testBit` 63
carryLo = srcLo `testBit` 63
{-
const uint64_t gf_mask = cpu_to_le64(0x8000000000000000ULL);
uint64_t r = ((a->q[1] & gf_mask) ? cpu_to_le64(0x87) : 0);
a->q[1] = cpu_to_le64((le64_to_cpu(a->q[1]) << 1) | (a->q[0] & gf_mask ? 1 : 0));
a->q[0] = cpu_to_le64(le64_to_cpu(a->q[0]) << 1) ^ r;
-}

View File

@ -0,0 +1,20 @@
-- |
-- Module : Crypto.Cipher.Types.Stream
-- License : BSD-style
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
-- Stability : Stable
-- Portability : Excellent
--
-- stream cipher basic types
--
module Crypto.Cipher.Types.Stream
( StreamCipher(..)
) where
import Crypto.Cipher.Types.Base
import Data.ByteString (ByteString)
-- | Symmetric stream cipher class
class Cipher cipher => StreamCipher cipher where
-- | Combine using the stream cipher
streamCombine :: cipher -> ByteString -> (ByteString, cipher)

View File

@ -0,0 +1,19 @@
-- |
-- Module : Crypto.Cipher.Types.Utils
-- License : BSD-style
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
-- Stability : Stable
-- Portability : Excellent
--
-- basic utility for cipher related stuff
--
module Crypto.Cipher.Types.Utils where
import Crypto.Internal.ByteArray
chunk :: ByteArray b => Int -> b -> [b]
chunk sz bs = split bs
where split b | byteArrayLength b <= sz = [b]
| otherwise =
let (b1, b2) = byteArraySplit sz b
in b1 : split b2

12
Crypto/Error.hs Normal file
View File

@ -0,0 +1,12 @@
-- |
-- Module : Crypto.Error
-- License : BSD-style
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
-- Stability : Stable
-- Portability : Excellent
--
module Crypto.Error
( module Crypto.Error.Types
) where
import Crypto.Error.Types

68
Crypto/Error/Types.hs Normal file
View File

@ -0,0 +1,68 @@
-- |
-- Module : Crypto.Error.Types
-- License : BSD-style
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
-- Stability : stable
-- Portability : Good
--
-- Cryptographic Error enumeration and handling
--
{-# LANGUAGE DeriveDataTypeable #-}
module Crypto.Error.Types
( CryptoError(..)
, CryptoFailable(..)
, throwCryptoErrorIO
, throwCryptoError
) where
import qualified Control.Exception as E
import Data.Data
import Crypto.Internal.Imports
-- | Enumeration of all possible errors that can be found in this library
data CryptoError =
-- symmetric cipher errors
CryptoError_KeySizeInvalid
| CryptoError_IvSizeInvalid
deriving (Show,Eq,Enum,Data,Typeable)
instance E.Exception CryptoError
-- | A simple Either like type to represent a computation that can fail
--
-- 2 possibles values are:
-- * 'CryptoPassed' :
data CryptoFailable a =
CryptoPassed a
| CryptoFailed CryptoError
instance Functor CryptoFailable where
fmap f (CryptoPassed a) = CryptoPassed (f a)
fmap _ (CryptoFailed r) = CryptoFailed r
instance Applicative CryptoFailable where
pure a = CryptoPassed a
(<*>) fm m = fm >>= \p -> m >>= \r2 -> return (p r2)
instance Monad CryptoFailable where
return a = CryptoPassed a
(>>=) m1 m2 = do
case m1 of
CryptoPassed a -> m2 a
CryptoFailed e -> CryptoFailed e
throwCryptoErrorIO :: CryptoFailable a -> IO a
throwCryptoErrorIO (CryptoFailed e) = E.throwIO e
throwCryptoErrorIO (CryptoPassed r) = return r
throwCryptoError :: CryptoFailable a -> a
throwCryptoError (CryptoFailed e) = E.throw e
throwCryptoError (CryptoPassed r) = r
{-
eitherCryptoError :: CryptoFailable a -> Either CryptoError a
eitherCryptoError = undefined
maybeCryptoError :: CryptoFailable a -> Maybe a
maybeCryptoError = undefined
-}

View File

@ -12,47 +12,69 @@
{-# LANGUAGE UnboxedTuples #-} {-# LANGUAGE UnboxedTuples #-}
module Crypto.Internal.ByteArray module Crypto.Internal.ByteArray
( ByteArray(..) ( ByteArray(..)
, ByteArrayAccess(..)
, byteArrayAllocAndFreeze , byteArrayAllocAndFreeze
, empty , empty
-- , split , byteArrayCopyAndFreeze
, byteArraySplit
, byteArrayXor
, byteArrayEq
, byteArrayConstEq
, byteArrayConcat
, byteArrayToBS
, byteArrayFromBS
, byteArrayToW64BE
, byteArrayToW64LE
, byteArrayMapAsWord64
, byteArrayMapAsWord128
) where ) where
import Control.Applicative ((<$>), (<*>))
import Data.Word
import Data.SecureMem import Data.SecureMem
import Crypto.Internal.Memory import Crypto.Internal.Memory
import Crypto.Internal.Compat import Crypto.Internal.Compat
import Crypto.Internal.Endian
import Crypto.Internal.Bytes (bufXor, bufCopy)
import Crypto.Internal.Words
import Foreign.Ptr import Foreign.Ptr
import Foreign.Storable
import Foreign.ForeignPtr import Foreign.ForeignPtr
import Data.ByteString (ByteString) import Data.ByteString (ByteString)
import qualified Data.ByteString as B (length) import qualified Data.ByteString as B (length)
import qualified Data.ByteString.Internal as B import qualified Data.ByteString.Internal as B
class ByteArray ba where class ByteArrayAccess ba where
byteArrayAlloc :: Int -> (Ptr p -> IO ()) -> IO ba
byteArrayLength :: ba -> Int byteArrayLength :: ba -> Int
withByteArray :: ba -> (Ptr p -> IO a) -> IO a withByteArray :: ba -> (Ptr p -> IO a) -> IO a
instance ByteArray Bytes where class ByteArrayAccess ba => ByteArray ba where
byteArrayAlloc = bytesAlloc byteArrayAlloc :: Int -> (Ptr p -> IO ()) -> IO ba
instance ByteArrayAccess Bytes where
byteArrayLength = bytesLength byteArrayLength = bytesLength
withByteArray = withBytes withByteArray = withBytes
instance ByteArray Bytes where
byteArrayAlloc = bytesAlloc
instance ByteArrayAccess ByteString where
byteArrayLength = B.length
withByteArray b f = withForeignPtr fptr $ \ptr -> f (ptr `plusPtr` off)
where (fptr, off, _) = B.toForeignPtr b
instance ByteArray ByteString where instance ByteArray ByteString where
byteArrayAlloc sz f = do byteArrayAlloc sz f = do
fptr <- B.mallocByteString sz fptr <- B.mallocByteString sz
withForeignPtr fptr (f . castPtr) withForeignPtr fptr (f . castPtr)
return $! B.PS fptr 0 sz return $! B.PS fptr 0 sz
byteArrayLength = B.length
withByteArray b f = withForeignPtr fptr $ \ptr -> f (ptr `plusPtr` off)
where (fptr, off, _) = B.toForeignPtr b
instance ByteArrayAccess SecureMem where
byteArrayLength = secureMemGetSize
withByteArray b f = withSecureMemPtr b (f . castPtr)
instance ByteArray SecureMem where instance ByteArray SecureMem where
byteArrayAlloc sz f = do byteArrayAlloc sz f = do
out <- allocateSecureMem sz out <- allocateSecureMem sz
withSecureMemPtr out (f . castPtr) withSecureMemPtr out (f . castPtr)
return out return out
byteArrayLength = secureMemGetSize
withByteArray b f = withSecureMemPtr b (f . castPtr)
byteArrayAllocAndFreeze :: ByteArray a => Int -> (Ptr p -> IO ()) -> a byteArrayAllocAndFreeze :: ByteArray a => Int -> (Ptr p -> IO ()) -> a
byteArrayAllocAndFreeze sz f = unsafeDoIO (byteArrayAlloc sz f) byteArrayAllocAndFreeze sz f = unsafeDoIO (byteArrayAlloc sz f)
@ -60,9 +82,22 @@ byteArrayAllocAndFreeze sz f = unsafeDoIO (byteArrayAlloc sz f)
empty :: ByteArray a => a empty :: ByteArray a => a
empty = unsafeDoIO (byteArrayAlloc 0 $ \_ -> return ()) empty = unsafeDoIO (byteArrayAlloc 0 $ \_ -> return ())
{- -- | Create a xor of bytes between a and b.
split :: ByteArray bs => Int -> bs -> (bs, bs) --
split n bs -- the returns byte array is the size of the smallest input.
byteArrayXor :: (ByteArrayAccess a, ByteArrayAccess b, ByteArray c) => a -> b -> c
byteArrayXor a b =
byteArrayAllocAndFreeze n $ \pc ->
withByteArray a $ \pa ->
withByteArray b $ \pb ->
bufXor pc pa pb n
where
n = min la lb
la = byteArrayLength a
lb = byteArrayLength b
byteArraySplit :: ByteArray bs => Int -> bs -> (bs, bs)
byteArraySplit n bs
| n <= 0 = (empty, bs) | n <= 0 = (empty, bs)
| n >= len = (bs, empty) | n >= len = (bs, empty)
| otherwise = unsafeDoIO $ do | otherwise = unsafeDoIO $ do
@ -71,4 +106,110 @@ split n bs
b2 <- byteArrayAlloc (len - n) $ \r -> bufCopy r (p `plusPtr` n) (len - n) b2 <- byteArrayAlloc (len - n) $ \r -> bufCopy r (p `plusPtr` n) (len - n)
return (b1, b2) return (b1, b2)
where len = byteArrayLength bs where len = byteArrayLength bs
-}
byteArrayConcat :: ByteArray bs => [bs] -> bs
byteArrayConcat [] = empty
byteArrayConcat allBs = byteArrayAllocAndFreeze total (loop allBs)
where
total = sum $ map byteArrayLength allBs
loop [] _ = return ()
loop (b:bs) dst = do
let sz = byteArrayLength b
withByteArray b $ \p -> bufCopy dst p sz
loop bs (dst `plusPtr` sz)
byteArrayCopyAndFreeze :: (ByteArray bs1, ByteArray bs2) => bs1 -> (Ptr p -> IO ()) -> bs2
byteArrayCopyAndFreeze bs f =
byteArrayAllocAndFreeze (byteArrayLength bs) $ \d -> do
withByteArray bs $ \s -> bufCopy d s (byteArrayLength bs)
f (castPtr d)
byteArrayEq :: (ByteArrayAccess bs1, ByteArrayAccess bs2) => bs1 -> bs2 -> Bool
byteArrayEq b1 b2
| l1 /= l2 = False
| otherwise = unsafeDoIO $
withByteArray b1 $ \p1 ->
withByteArray b2 $ \p2 ->
loop l1 p1 p2
where
l1 = byteArrayLength b1
l2 = byteArrayLength b2
loop :: Int -> Ptr Word8 -> Ptr Word8 -> IO Bool
loop 0 _ _ = return True
loop i p1 p2 = do
e <- (==) <$> peek p1 <*> peek p2
if e then loop (i-1) (p1 `plusPtr` 1) (p2 `plusPtr` 1) else return False
-- | A constant time equality test for 2 ByteArrayAccess values.
--
-- If values are of 2 different sizes, the function will abort early
-- without comparing any bytes.
--
-- compared to == , this function will go over all the bytes
-- present before yielding a result even when knowing the
-- overall result early in the processing.
byteArrayConstEq :: (ByteArrayAccess bs1, ByteArrayAccess bs2) => bs1 -> bs2 -> Bool
byteArrayConstEq b1 b2
| l1 /= l2 = False
| otherwise = unsafeDoIO $
withByteArray b1 $ \p1 ->
withByteArray b2 $ \p2 ->
loop l1 True p1 p2
where
l1 = byteArrayLength b1
l2 = byteArrayLength b2
loop :: Int -> Bool -> Ptr Word8 -> Ptr Word8 -> IO Bool
loop 0 !ret _ _ = return ret
loop i !ret p1 p2 = do
e <- (==) <$> peek p1 <*> peek p2
loop (i-1) (ret &&! e) (p1 `plusPtr` 1) (p2 `plusPtr` 1)
-- Bool == Bool
(&&!) :: Bool -> Bool -> Bool
True &&! True = True
True &&! False = False
False &&! True = False
False &&! False = False
byteArrayToBS :: ByteArray bs => bs -> ByteString
byteArrayToBS bs = byteArrayCopyAndFreeze bs (\_ -> return ())
byteArrayFromBS :: ByteArray bs => ByteString -> bs
byteArrayFromBS bs = byteArrayCopyAndFreeze bs (\_ -> return ())
byteArrayToW64BE :: ByteArrayAccess bs => bs -> Int -> Word64
byteArrayToW64BE bs ofs = unsafeDoIO $ withByteArray bs $ \p -> fromBE64 <$> peek (p `plusPtr` ofs)
byteArrayToW64LE :: ByteArrayAccess bs => bs -> Int -> Word64
byteArrayToW64LE bs ofs = unsafeDoIO $ withByteArray bs $ \p -> fromLE64 <$> peek (p `plusPtr` ofs)
byteArrayMapAsWord128 :: ByteArray bs => (Word128 -> Word128) -> bs -> bs
byteArrayMapAsWord128 f bs =
byteArrayAllocAndFreeze len $ \dst ->
withByteArray bs $ \src ->
loop (len `div` 16) dst src
where
len = byteArrayLength bs
loop 0 _ _ = return ()
loop i d s = do
w1 <- peek s
w2 <- peek (s `plusPtr` 8)
let (Word128 r1 r2) = f (Word128 (fromBE64 w1) (fromBE64 w2))
poke d (toBE64 r1)
poke (d `plusPtr` 8) (toBE64 r2)
loop (i-1) (d `plusPtr` 16) (s `plusPtr` 16)
byteArrayMapAsWord64 :: ByteArray bs => (Word64 -> Word64) -> bs -> bs
byteArrayMapAsWord64 f bs =
byteArrayAllocAndFreeze len $ \dst ->
withByteArray bs $ \src ->
loop (len `div` 8) dst src
where
len = byteArrayLength bs
loop 0 _ _ = return ()
loop i d s = do
w <- peek s
let r = f (fromBE64 w)
poke d (toBE64 r)
loop (i-1) (d `plusPtr` 8) (s `plusPtr` 8)

View File

@ -12,15 +12,12 @@
module Crypto.Internal.Compat module Crypto.Internal.Compat
( unsafeDoIO ( unsafeDoIO
, popCount , popCount
, byteSwap64
) where ) where
import System.IO.Unsafe import System.IO.Unsafe
#if MIN_VERSION_base(4,5,0) import Data.Word
import Data.Bits (popCount) import Data.Bits
#else
import Data.Word (Word64)
import Data.Bits (testBit, shiftR)
#endif
-- | perform io for hashes that do allocation and ffi. -- | perform io for hashes that do allocation and ffi.
-- unsafeDupablePerformIO is used when possible as the -- unsafeDupablePerformIO is used when possible as the
@ -40,3 +37,12 @@ popCount n = loop 0 n
where loop c 0 = c where loop c 0 = c
loop c i = loop (c + if testBit c 0 then 1 else 0) (i `shiftR` 1) loop c i = loop (c + if testBit c 0 then 1 else 0) (i `shiftR` 1)
#endif #endif
#if !(MIN_VERSION_base(4,7,0))
byteSwap64 :: Word64 -> Word64
byteSwap64 w =
(w `shiftR` 56) .|. (w `shiftL` 56)
.|. ((w `shiftR` 40) .&. 0xff00) .|. ((w .&. 0xff00) `shiftL` 40)
.|. ((w `shiftR` 24) .&. 0xff0000) .|. ((w .&. 0xff0000) `shiftL` 24)
.|. ((w `shiftR` 8) .&. 0xff000000) .|. ((w .&. 0xff000000) `shiftL` 8)
#endif

View File

@ -0,0 +1,49 @@
-- |
-- Module : Crypto.Internal.CompatPrim
-- License : BSD-style
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
-- Stability : stable
-- Portability : Compat
--
-- This module try to keep all the difference between versions of ghc primitive
-- or other needed packages, so that modules don't need to use CPP.
--
-- Note that MagicHash and CPP conflicts in places, making it "more interesting"
-- to write compat code for primitives
--
{-# LANGUAGE CPP #-}
{-# LANGUAGE MagicHash #-}
module Crypto.Internal.CompatPrim
( be32Prim
, byteswap32Prim
, booleanPrim
) where
import GHC.Prim
#ifdef ARCH_IS_LITTLE_ENDIAN
be32Prim :: Word# -> Word#
be32Prim = byteswap32Prim
#else
be32Prim w = w
#endif
byteswap32Prim :: Word# -> Word#
#if __GLASGOW_HASKELL__ >= 708
byteswap32Prim w = byteSwap32# w
#else
byteswap32Prim w =
let a = uncheckedShiftL# w 24#
b = and# (uncheckedShiftL# w 8#) 0x00ff0000##
c = and# (uncheckedShiftRL# w 8#) 0x0000ff00##
d = and# (uncheckedShiftRL# w 24#) 0x000000ff##
in or# a (or# b (or# c d))
#endif
#if __GLASGOW_HASKELL__ >= 708
booleanPrim :: Int# -> Bool
booleanPrim v = tagToEnum# v
#else
booleanPrim :: Bool -> Bool
booleanPrim b = b
#endif

41
Crypto/Internal/Endian.hs Normal file
View File

@ -0,0 +1,41 @@
-- |
-- Module : Crypto.Internal.Endian
-- License : BSD-style
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
-- Stability : stable
-- Portability : good
--
{-# LANGUAGE CPP #-}
module Crypto.Internal.Endian
( fromBE64, toBE64
, fromLE64, toLE64
) where
import Crypto.Internal.Compat (byteSwap64)
import Data.Word (Word64)
#ifdef ARCH_IS_LITTLE_ENDIAN
fromLE64 :: Word64 -> Word64
fromLE64 = id
toLE64 :: Word64 -> Word64
toLE64 = id
fromBE64 :: Word64 -> Word64
fromBE64 = byteSwap64
toBE64 :: Word64 -> Word64
toBE64 = byteSwap64
#else
fromLE64 :: Word64 -> Word64
fromLE64 = byteSwap64
toLE64 :: Word64 -> Word64
toLE64 = byteSwap64
fromBE64 :: Word64 -> Word64
fromBE64 = id
toBE64 :: Word64 -> Word64
toBE64 = id
#endif

View File

@ -0,0 +1,15 @@
-- |
-- Module : Crypto.Internal.Imports
-- License : BSD-style
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
-- Stability : experimental
-- Portability : unknown
--
{-# LANGUAGE BangPatterns #-}
module Crypto.Internal.Imports
( module X
) where
import Data.Word as X
import Control.Applicative as X
import Control.Monad as X (forM, forM_, void)

View File

@ -0,0 +1,137 @@
-- |
-- Module : Crypto.Internal.Compat
-- License : BSD-style
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
-- Stability : stable
-- Portability : Good
--
-- Small and self contained array representation
-- with limited safety for internal use.
--
-- the array produced should never be exposed to the user directly
--
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE UnboxedTuples #-}
module Crypto.Internal.WordArray
( Array8
, Array32
, Array64
, MutableArray32
, array8
, array32
, mutableArray32
, array64
, arrayRead8
, arrayRead32
, arrayRead64
, mutableArrayRead32
, mutableArrayWrite32
, mutableArrayWriteXor32
, mutableArray32FromAddrBE
, mutableArray32Freeze
) where
import Data.Word
import Data.Bits (xor)
import Crypto.Internal.Compat
import Crypto.Internal.CompatPrim
import GHC.Prim
import GHC.Types
import GHC.Word
data Array8 = Array8 Addr#
data Array32 = Array32 ByteArray#
data Array64 = Array64 ByteArray#
data MutableArray32 = MutableArray32 (MutableByteArray# RealWorld)
array8 :: Addr# -> Array8
array8 = Array8
array32 :: Int -> [Word32] -> Array32
array32 (I# n) l = unsafeDoIO $ IO $ \s ->
case newAlignedPinnedByteArray# (n *# 4#) 4# s of
(# s', mbarr #) -> loop 0# s' mbarr l
where
loop _ st mb [] = freezeArray mb st
loop i st mb ((W32# x):xs)
| booleanPrim (i ==# n) = freezeArray mb st
| otherwise =
let st' = writeWord32Array# mb i x st
in loop (i +# 1#) st' mb xs
freezeArray mb st =
case unsafeFreezeByteArray# mb st of
(# st', b #) -> (# st', Array32 b #)
{-# NOINLINE array32 #-}
array64 :: Int -> [Word64] -> Array64
array64 (I# n) l = unsafeDoIO $ IO $ \s ->
case newAlignedPinnedByteArray# (n *# 8#) 8# s of
(# s', mbarr #) -> loop 0# s' mbarr l
where
loop _ st mb [] = freezeArray mb st
loop i st mb ((W64# x):xs)
| booleanPrim (i ==# n) = freezeArray mb st
| otherwise =
let st' = writeWord64Array# mb i x st
in loop (i +# 1#) st' mb xs
freezeArray mb st =
case unsafeFreezeByteArray# mb st of
(# st', b #) -> (# st', Array64 b #)
{-# NOINLINE array64 #-}
mutableArray32 :: Int -> [Word32] -> IO MutableArray32
mutableArray32 (I# n) l = IO $ \s ->
case newAlignedPinnedByteArray# (n *# 4#) 4# s of
(# s', mbarr #) -> loop 0# s' mbarr l
where
loop _ st mb [] = (# st, MutableArray32 mb #)
loop i st mb ((W32# x):xs)
| booleanPrim (i ==# n) = (# st, MutableArray32 mb #)
| otherwise =
let st' = writeWord32Array# mb i x st
in loop (i +# 1#) st' mb xs
mutableArray32FromAddrBE :: Int -> Addr# -> IO MutableArray32
mutableArray32FromAddrBE (I# n) a = IO $ \s ->
case newAlignedPinnedByteArray# (n *# 4#) 4# s of
(# s', mbarr #) -> loop 0# s' mbarr
where
loop i st mb
| booleanPrim (i ==# n) = (# st, MutableArray32 mb #)
| otherwise =
let st' = writeWord32Array# mb i (be32Prim (indexWord32OffAddr# a i)) st
in loop (i +# 1#) st' mb
mutableArray32Freeze :: MutableArray32 -> IO Array32
mutableArray32Freeze (MutableArray32 mb) = IO $ \st ->
case unsafeFreezeByteArray# mb st of
(# st', b #) -> (# st', Array32 b #)
arrayRead8 :: Array8 -> Int -> Word8
arrayRead8 (Array8 a) (I# o) = W8# (indexWord8OffAddr# a o)
{-# INLINE arrayRead8 #-}
arrayRead32 :: Array32 -> Int -> Word32
arrayRead32 (Array32 b) (I# o) = W32# (indexWord32Array# b o)
{-# INLINE arrayRead32 #-}
arrayRead64 :: Array64 -> Int -> Word64
arrayRead64 (Array64 b) (I# o) = W64# (indexWord64Array# b o)
{-# INLINE arrayRead64 #-}
mutableArrayRead32 :: MutableArray32 -> Int -> IO Word32
mutableArrayRead32 (MutableArray32 m) (I# o) = IO $ \s -> case readWord32Array# m o s of (# s', e #) -> (# s', W32# e #)
{-# INLINE mutableArrayRead32 #-}
mutableArrayWrite32 :: MutableArray32 -> Int -> Word32 -> IO ()
mutableArrayWrite32 (MutableArray32 m) (I# o) (W32# w) = IO $ \s -> let s' = writeWord32Array# m o w s in (# s', () #)
{-# INLINE mutableArrayWrite32 #-}
mutableArrayWriteXor32 :: MutableArray32 -> Int -> Word32 -> IO ()
mutableArrayWriteXor32 m o w =
mutableArrayRead32 m o >>= \wOld -> mutableArrayWrite32 m o (wOld `xor` w)
{-# INLINE mutableArrayWriteXor32 #-}

26
Crypto/Internal/Words.hs Normal file
View File

@ -0,0 +1,26 @@
-- |
-- Module : Crypto.Internal.Words
-- License : BSD-style
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
-- Stability : experimental
-- Portability : unknown
--
-- Extra Word size
--
module Crypto.Internal.Words
( Word128(..)
, w64to32
, w32to64
) where
import Data.Word
import Data.Bits
-- should probably use crypto large word ?
data Word128 = Word128 !Word64 !Word64 deriving (Show, Eq)
w64to32 :: Word64 -> (Word32, Word32)
w64to32 w = (fromIntegral (w `shiftR` 32), fromIntegral w)
w32to64 :: (Word32, Word32) -> Word64
w32to64 (x1, x2) = ((fromIntegral x1) `shiftL` 32) .|. (fromIntegral x2)

View File

@ -17,6 +17,7 @@ extra-doc-files: README.md
extra-source-files: cbits/*.h extra-source-files: cbits/*.h
cbits/aes/*.h cbits/aes/*.h
cbits/aes/x86ni_impl.c cbits/aes/x86ni_impl.c
tests/*.hs
source-repository head source-repository head
type: git type: git
@ -27,10 +28,17 @@ Flag support_aesni
Default: True Default: True
Library Library
Exposed-modules: Crypto.Cipher.ChaCha Exposed-modules: Crypto.Cipher.AES
Crypto.Cipher.Salsa Crypto.Cipher.Blowfish
Crypto.Cipher.Camellia
Crypto.Cipher.ChaCha
Crypto.Cipher.DES
Crypto.Cipher.RC4 Crypto.Cipher.RC4
Crypto.Cipher.Salsa
Crypto.Cipher.TripleDES
Crypto.Cipher.Types
Crypto.Data.AFIS Crypto.Data.AFIS
Crypto.Error
Crypto.MAC.Poly1305 Crypto.MAC.Poly1305
Crypto.MAC.HMAC Crypto.MAC.HMAC
Crypto.Number.Basic Crypto.Number.Basic
@ -79,7 +87,20 @@ Library
Crypto.Random.Entropy Crypto.Random.Entropy
Crypto.Random.EntropyPool Crypto.Random.EntropyPool
Crypto.Random.Entropy.Unsafe Crypto.Random.Entropy.Unsafe
Crypto.Internal.ByteArray
Other-modules: Crypto.Cipher.AES.Internal Other-modules: Crypto.Cipher.AES.Internal
Crypto.Cipher.Blowfish.Box
Crypto.Cipher.Blowfish.Primitive
Crypto.Cipher.Camellia.Primitive
Crypto.Cipher.DES.Primitive
Crypto.Cipher.DES.Serialization
Crypto.Cipher.Types.AEAD
Crypto.Cipher.Types.Base
Crypto.Cipher.Types.Block
Crypto.Cipher.Types.GF
Crypto.Cipher.Types.Stream
Crypto.Cipher.Types.Utils
Crypto.Error.Types
Crypto.Hash.Utils Crypto.Hash.Utils
Crypto.Hash.Utils.Cpu Crypto.Hash.Utils.Cpu
Crypto.Hash.Types Crypto.Hash.Types
@ -105,9 +126,13 @@ Library
Crypto.PubKey.Internal Crypto.PubKey.Internal
Crypto.PubKey.ElGamal Crypto.PubKey.ElGamal
Crypto.Internal.Compat Crypto.Internal.Compat
Crypto.Internal.CompatPrim
Crypto.Internal.Bytes Crypto.Internal.Bytes
Crypto.Internal.ByteArray Crypto.Internal.Endian
Crypto.Internal.Imports
Crypto.Internal.Memory Crypto.Internal.Memory
Crypto.Internal.Words
Crypto.Internal.WordArray
Build-depends: base >= 4.3 && < 5 Build-depends: base >= 4.3 && < 5
, bytestring , bytestring
, securemem >= 0.1.7 , securemem >= 0.1.7
@ -139,6 +164,10 @@ Library
, cbits/cryptonite_whirlpool.c , cbits/cryptonite_whirlpool.c
, cbits/cryptonite_scrypt.c , cbits/cryptonite_scrypt.c
include-dirs: cbits include-dirs: cbits
-- FIXME armel or mispel is also little endian.
-- might be a good idea to also add a runtime autodetect mode.
-- ARCH_ENDIAN_UNKNOWN
if (arch(i386) || arch(x86_64)) if (arch(i386) || arch(x86_64))
CPP-options: -DARCH_IS_LITTLE_ENDIAN CPP-options: -DARCH_IS_LITTLE_ENDIAN

View File

@ -5,7 +5,7 @@
{ "path": "cbits" }, { "path": "cbits" },
{ "path": "tests", "file_exclude_patterns": ["*.html"] }, { "path": "tests", "file_exclude_patterns": ["*.html"] },
{ "path": "benchs" }, { "path": "benchs" },
{ "path": "gen" }, { "path": "gen" }
], ],
"settings": "settings":
{ {

View File

@ -1,3 +1,4 @@
{-# LANGUAGE ViewPatterns #-}
module BlockCipher module BlockCipher
( KAT_ECB(..) ( KAT_ECB(..)
, KAT_CBC(..) , KAT_CBC(..)
@ -5,21 +6,30 @@ module BlockCipher
, KAT_CTR(..) , KAT_CTR(..)
, KAT_XTS(..) , KAT_XTS(..)
, KAT_AEAD(..) , KAT_AEAD(..)
, testECB , KATs(..)
, testKatCBC , defaultKATs
, testKatCFB , testBlockCipher
, testKatCTR
, testKatXTS
, testKatAEAD
, CipherInfo , CipherInfo
) where ) where
import Imports import Imports
import Data.Maybe
import Crypto.Error
import Crypto.Cipher.Types
import Crypto.Internal.ByteArray
import qualified Data.ByteString as B
------------------------------------------------------------------------
-- KAT
------------------------------------------------------------------------
type BlockSize = Int type BlockSize = Int
type KeySize = Int type KeySize = Int
type CipherInfo a = (BlockSize, KeySize, ByteString -> a) type CipherInfo a = (BlockSize, KeySize, ByteString -> a)
instance Show (IV c) where
show _ = "IV"
-- | ECB KAT -- | ECB KAT
data KAT_ECB = KAT_ECB data KAT_ECB = KAT_ECB
{ ecbKey :: ByteString -- ^ Key { ecbKey :: ByteString -- ^ Key
@ -71,6 +81,20 @@ data KAT_AEAD = KAT_AEAD
, aeadTag :: ByteString -- ^ expected tag , aeadTag :: ByteString -- ^ expected tag
} deriving (Show,Eq) } deriving (Show,Eq)
-- | all the KATs. use defaultKATs to prevent compilation error
-- from future expansion of this data structure
data KATs = KATs
{ kat_ECB :: [KAT_ECB]
, kat_CBC :: [KAT_CBC]
, kat_CFB :: [KAT_CFB]
, kat_CTR :: [KAT_CTR]
, kat_XTS :: [KAT_XTS]
, kat_AEAD :: [KAT_AEAD]
} deriving (Show,Eq)
defaultKATs = KATs [] [] [] [] [] []
{-
testECB (_, _, cipherInit) ecbEncrypt ecbDecrypt kats = testECB (_, _, cipherInit) ecbEncrypt ecbDecrypt kats =
testGroup "ECB" (concatMap katTest (zip is kats) {- ++ propTests-}) testGroup "ECB" (concatMap katTest (zip is kats) {- ++ propTests-})
where katTest (i,d) = where katTest (i,d) =
@ -124,6 +148,312 @@ testKatAEAD cipherInit aeadInit aeadAppendHeader aeadEncrypt aeadDecrypt aeadFin
(dbs,aeadDFinal) = aeadDecrypt aeadHeaded (aeadCiphertext d) (dbs,aeadDFinal) = aeadDecrypt aeadHeaded (aeadCiphertext d)
etag = aeadFinalize aeadEFinal (aeadTaglen d) etag = aeadFinalize aeadEFinal (aeadTaglen d)
dtag = aeadFinalize aeadDFinal (aeadTaglen d) dtag = aeadFinalize aeadDFinal (aeadTaglen d)
-}
is :: [Int] testKATs :: BlockCipher cipher
is = [1..] => KATs
-> cipher
-> TestTree
testKATs kats cipher = testGroup "KAT"
( maybeGroup makeECBTest "ECB" (kat_ECB kats)
++ maybeGroup makeCBCTest "CBC" (kat_CBC kats)
++ maybeGroup makeCFBTest "CFB" (kat_CFB kats)
++ maybeGroup makeCTRTest "CTR" (kat_CTR kats)
-- ++ maybeGroup makeXTSTest "XTS" (kat_XTS kats)
-- ++ maybeGroup makeAEADTest "AEAD" (kat_AEAD kats)
)
where makeECBTest i d =
[ testCase ("E" ++ i) (ecbEncrypt ctx (ecbPlaintext d) @?= ecbCiphertext d)
, testCase ("D" ++ i) (ecbDecrypt ctx (ecbCiphertext d) @?= ecbPlaintext d)
]
where ctx = cipherInitNoErr (cipherMakeKey cipher $ ecbKey d)
makeCBCTest i d =
[ testCase ("E" ++ i) (cbcEncrypt ctx iv (cbcPlaintext d) @?= cbcCiphertext d)
, testCase ("D" ++ i) (cbcDecrypt ctx iv (cbcCiphertext d) @?= cbcPlaintext d)
]
where ctx = cipherInitNoErr (cipherMakeKey cipher $ cbcKey d)
iv = cipherMakeIV cipher $ cbcIV d
makeCFBTest i d =
[ testCase ("E" ++ i) (cfbEncrypt ctx iv (cfbPlaintext d) @?= cfbCiphertext d)
, testCase ("D" ++ i) (cfbDecrypt ctx iv (cfbCiphertext d) @?= cfbPlaintext d)
]
where ctx = cipherInitNoErr (cipherMakeKey cipher $ cfbKey d)
iv = cipherMakeIV cipher $ cfbIV d
makeCTRTest i d =
[ testCase ("E" ++ i) (ctrCombine ctx iv (ctrPlaintext d) @?= ctrCiphertext d)
, testCase ("D" ++ i) (ctrCombine ctx iv (ctrCiphertext d) @?= ctrPlaintext d)
]
where ctx = cipherInitNoErr (cipherMakeKey cipher $ ctrKey d)
iv = cipherMakeIV cipher $ ctrIV d
{-
makeXTSTest i d =
[ testCase ("E" ++ i) (xtsEncrypt ctx iv 0 (xtsPlaintext d) @?= xtsCiphertext d)
, testCase ("D" ++ i) (xtsDecrypt ctx iv 0 (xtsCiphertext d) @?= xtsPlaintext d)
]
where ctx1 = cipherInit (cipherMakeKey cipher $ xtsKey1 d)
ctx2 = cipherInit (cipherMakeKey cipher $ xtsKey2 d)
ctx = (ctx1, ctx2)
iv = cipherMakeIV cipher $ xtsIV d
makeAEADTest i d =
[ testCase ("AE" ++ i) (etag @?= aeadTag d)
, testCase ("AD" ++ i) (dtag @?= aeadTag d)
, testCase ("E" ++ i) (ebs @?= aeadCiphertext d)
, testCase ("D" ++ i) (dbs @?= aeadPlaintext d)
]
where ctx = cipherInit (cipherMakeKey cipher $ aeadKey d)
aead = maybe (error $ "cipher doesn't support aead mode: " ++ show (aeadMode d)) id
$ aeadInit (aeadMode d) ctx (aeadIV d)
aeadHeaded = aeadAppendHeader aead (aeadHeader d)
(ebs,aeadEFinal) = aeadEncrypt aeadHeaded (aeadPlaintext d)
(dbs,aeadDFinal) = aeadDecrypt aeadHeaded (aeadCiphertext d)
etag = aeadFinalize aeadEFinal (aeadTaglen d)
dtag = aeadFinalize aeadDFinal (aeadTaglen d)
-}
cipherInitNoErr :: BlockCipher c => Key c -> c
cipherInitNoErr (Key k) =
case cipherInit k of
CryptoPassed a -> a
CryptoFailed e -> error (show e)
------------------------------------------------------------------------
-- Properties
------------------------------------------------------------------------
-- | any sized bytestring
newtype Plaintext a = Plaintext { unPlaintext :: B.ByteString }
deriving (Show,Eq)
-- | A multiple of blocksize bytestring
newtype PlaintextBS a = PlaintextBS { unPlaintextBS :: B.ByteString }
deriving (Show,Eq)
newtype Key a = Key ByteString
deriving (Show,Eq)
-- | a ECB unit test
data ECBUnit a = ECBUnit (Key a) (PlaintextBS a)
deriving (Eq)
-- | a CBC unit test
data CBCUnit a = CBCUnit (Key a) (IV a) (PlaintextBS a)
deriving (Eq)
-- | a CBC unit test
data CFBUnit a = CFBUnit (Key a) (IV a) (PlaintextBS a)
deriving (Eq)
-- | a CFB unit test
data CFB8Unit a = CFB8Unit (Key a) (IV a) (Plaintext a)
deriving (Eq)
-- | a CTR unit test
data CTRUnit a = CTRUnit (Key a) (IV a) (Plaintext a)
deriving (Eq)
-- | a XTS unit test
data XTSUnit a = XTSUnit (Key a) (Key a) (IV a) (PlaintextBS a)
deriving (Eq)
-- | a AEAD unit test
data AEADUnit a = AEADUnit (Key a) B.ByteString (Plaintext a) (Plaintext a)
deriving (Eq)
-- | Stream cipher unit test
data StreamUnit a = StreamUnit (Key a) (Plaintext a)
deriving (Eq)
instance Show (ECBUnit a) where
show (ECBUnit key b) = "ECB(key=" ++ show key ++ ",input=" ++ show b ++ ")"
instance Show (CBCUnit a) where
show (CBCUnit key iv b) = "CBC(key=" ++ show key ++ ",iv=" ++ show iv ++ ",input=" ++ show b ++ ")"
instance Show (CFBUnit a) where
show (CFBUnit key iv b) = "CFB(key=" ++ show key ++ ",iv=" ++ show iv ++ ",input=" ++ show b ++ ")"
instance Show (CFB8Unit a) where
show (CFB8Unit key iv b) = "CFB8(key=" ++ show key ++ ",iv=" ++ show iv ++ ",input=" ++ show b ++ ")"
instance Show (CTRUnit a) where
show (CTRUnit key iv b) = "CTR(key=" ++ show key ++ ",iv=" ++ show iv ++ ",input=" ++ show b ++ ")"
instance Show (XTSUnit a) where
show (XTSUnit key1 key2 iv b) = "XTS(key1=" ++ show key1 ++ ",key2=" ++ show key2 ++ ",iv=" ++ show iv ++ ",input=" ++ show b ++ ")"
instance Show (AEADUnit a) where
show (AEADUnit key iv aad b) = "AEAD(key=" ++ show key ++ ",iv=" ++ show iv ++ ",aad=" ++ show (unPlaintext aad) ++ ",input=" ++ show b ++ ")"
instance Show (StreamUnit a) where
show (StreamUnit key b) = "Stream(key=" ++ show key ++ ",input=" ++ show b ++ ")"
-- | Generate an arbitrary valid key for a specific block cipher
generateKey :: Cipher a => Gen (Key a)
generateKey = keyFromCipher undefined
where keyFromCipher :: Cipher a => a -> Gen (Key a)
keyFromCipher cipher = do
sz <- case cipherKeySize cipher of
KeySizeRange low high -> choose (low, high)
KeySizeFixed v -> return v
KeySizeEnum l -> elements l
Key . B.pack <$> replicateM sz arbitrary
-- | Generate an arbitrary valid IV for a specific block cipher
generateIv :: BlockCipher a => Gen (IV a)
generateIv = ivFromCipher undefined
where ivFromCipher :: BlockCipher a => a -> Gen (IV a)
ivFromCipher cipher = fromJust . makeIV . B.pack <$> replicateM (blockSize cipher) arbitrary
-- | Generate an arbitrary valid IV for AEAD for a specific block cipher
generateIvAEAD :: Gen B.ByteString
generateIvAEAD = choose (12,90) >>= \sz -> (B.pack <$> replicateM sz arbitrary)
-- | Generate a plaintext multiple of blocksize bytes
generatePlaintextMultipleBS :: BlockCipher a => Gen (PlaintextBS a)
generatePlaintextMultipleBS = choose (1,128) >>= \size -> replicateM (size * 16) arbitrary >>= return . PlaintextBS . B.pack
-- | Generate any sized plaintext
generatePlaintext :: Gen (Plaintext a)
generatePlaintext = choose (0,324) >>= \size -> replicateM size arbitrary >>= return . Plaintext . B.pack
instance BlockCipher a => Arbitrary (ECBUnit a) where
arbitrary = ECBUnit <$> generateKey
<*> generatePlaintextMultipleBS
instance BlockCipher a => Arbitrary (CBCUnit a) where
arbitrary = CBCUnit <$> generateKey
<*> generateIv
<*> generatePlaintextMultipleBS
instance BlockCipher a => Arbitrary (CFBUnit a) where
arbitrary = CFBUnit <$> generateKey
<*> generateIv
<*> generatePlaintextMultipleBS
instance BlockCipher a => Arbitrary (CFB8Unit a) where
arbitrary = CFB8Unit <$> generateKey <*> generateIv <*> generatePlaintext
instance BlockCipher a => Arbitrary (CTRUnit a) where
arbitrary = CTRUnit <$> generateKey
<*> generateIv
<*> generatePlaintext
instance BlockCipher a => Arbitrary (XTSUnit a) where
arbitrary = XTSUnit <$> generateKey
<*> generateKey
<*> generateIv
<*> generatePlaintextMultipleBS
instance BlockCipher a => Arbitrary (AEADUnit a) where
arbitrary = AEADUnit <$> generateKey
<*> generateIvAEAD
<*> generatePlaintext
<*> generatePlaintext
instance StreamCipher a => Arbitrary (StreamUnit a) where
arbitrary = StreamUnit <$> generateKey
<*> generatePlaintext
testBlockCipherBasic :: BlockCipher a => a -> [TestTree]
testBlockCipherBasic cipher = [ testProperty "ECB" ecbProp ]
where ecbProp = toTests cipher
toTests :: BlockCipher a => a -> (ECBUnit a -> Bool)
toTests _ = testProperty_ECB
testProperty_ECB (ECBUnit key (unPlaintextBS -> plaintext)) = withCtx key $ \ctx ->
plaintext `assertEq` ecbDecrypt ctx (ecbEncrypt ctx plaintext)
testBlockCipherModes :: BlockCipher a => a -> [TestTree]
testBlockCipherModes cipher =
[ testProperty "CBC" cbcProp
, testProperty "CFB" cfbProp
--, testProperty "CFB8" cfb8Prop
, testProperty "CTR" ctrProp
]
where (cbcProp,cfbProp,ctrProp) = toTests cipher
toTests :: BlockCipher a
=> a
-> ((CBCUnit a -> Bool), (CFBUnit a -> Bool), {-(CFB8Unit a -> Bool),-} (CTRUnit a -> Bool))
toTests _ = (testProperty_CBC
,testProperty_CFB
--,testProperty_CFB8
,testProperty_CTR
)
testProperty_CBC (CBCUnit key testIV (unPlaintextBS -> plaintext)) = withCtx key $ \ctx ->
plaintext `assertEq` cbcDecrypt ctx testIV (cbcEncrypt ctx testIV plaintext)
testProperty_CFB (CFBUnit key testIV (unPlaintextBS -> plaintext)) = withCtx key $ \ctx ->
plaintext `assertEq` cfbDecrypt ctx testIV (cfbEncrypt ctx testIV plaintext)
{-
testProperty_CFB8 (CFB8Unit (cipherInit -> ctx) testIV (unPlaintext -> plaintext)) =
plaintext `assertEq` cfb8Decrypt ctx testIV (cfb8Encrypt ctx testIV plaintext)
-}
testProperty_CTR (CTRUnit key testIV (unPlaintext -> plaintext)) = withCtx key $ \ctx ->
plaintext `assertEq` ctrCombine ctx testIV (ctrCombine ctx testIV plaintext)
testBlockCipherAEAD :: BlockCipher a => a -> [TestTree]
testBlockCipherAEAD cipher =
[ testProperty "OCB" (aeadProp AEAD_OCB)
, testProperty "CCM" (aeadProp AEAD_CCM)
, testProperty "EAX" (aeadProp AEAD_EAX)
, testProperty "CWC" (aeadProp AEAD_CWC)
, testProperty "GCM" (aeadProp AEAD_GCM)
]
where aeadProp = toTests cipher
toTests :: BlockCipher a => a -> (AEADMode -> AEADUnit a -> Bool)
toTests _ = testProperty_AEAD
testProperty_AEAD mode (AEADUnit key testIV (unPlaintext -> aad) (unPlaintext -> plaintext)) = withCtx key $ \ctx ->
case aeadInit mode ctx testIV of
Just iniAead ->
let aead = aeadAppendHeader iniAead aad
(eText, aeadE) = aeadEncrypt aead plaintext
(dText, aeadD) = aeadDecrypt aead eText
eTag = aeadFinalize aeadE (blockSize ctx)
dTag = aeadFinalize aeadD (blockSize ctx)
in (plaintext `assertEq` dText) && (eTag `byteArrayEq` dTag)
Nothing -> True
withCtx :: Cipher c => Key c -> (c -> a) -> a
withCtx (Key key) f =
case cipherInit key of
CryptoFailed e -> error ("init failed: " ++ show e)
CryptoPassed ctx -> f ctx
{-
testBlockCipherXTS :: BlockCipher a => a -> [TestTree]
testBlockCipherXTS cipher = [testProperty "XTS" xtsProp]
where xtsProp = toTests cipher
toTests :: BlockCipher a => a -> (XTSUnit a -> Bool)
toTests _ = testProperty_XTS
testProperty_XTS (XTSUnit (cipherInit -> ctx1) (cipherInit -> ctx2) testIV (toBytes -> plaintext))
| blockSize ctx1 == 16 = plaintext `assertEq` xtsDecrypt (ctx1, ctx2) testIV 0 (xtsEncrypt (ctx1, ctx2) testIV 0 plaintext)
| otherwise = True
-}
-- | Test a generic block cipher for properties
-- related to block cipher modes.
testModes :: BlockCipher a => a -> [TestTree]
testModes cipher =
[ testGroup "decrypt.encrypt==id"
-- (testBlockCipherBasic cipher ++ testBlockCipherModes cipher ++ testBlockCipherAEAD cipher ++ testBlockCipherXTS cipher)
(testBlockCipherBasic cipher ++ testBlockCipherModes cipher ++ testBlockCipherAEAD cipher)
]
-- | Return tests for a specific blockcipher and a list of KATs
testBlockCipher :: BlockCipher a => KATs -> a -> TestTree
testBlockCipher kats cipher = testGroup (cipherName cipher)
( (if kats == defaultKATs then [] else [testKATs kats cipher])
++ testModes cipher
)
assertEq :: ByteString -> ByteString -> Bool
assertEq b1 b2 | b1 /= b2 = error ("b1: " ++ show b1 ++ " b2: " ++ show b2)
| otherwise = True
cipherMakeKey :: Cipher cipher => cipher -> ByteString -> Key cipher
cipherMakeKey _ bs = Key bs
cipherMakeIV :: BlockCipher cipher => cipher -> ByteString -> IV cipher
cipherMakeIV _ bs = fromJust $ makeIV bs
maybeGroup :: (String -> t -> [TestTree]) -> TestName -> [t] -> [TestTree]
maybeGroup mkTest groupName l
| null l = []
| otherwise = [testGroup groupName (concatMap (\(i, d) -> mkTest (show i) d) $ zip nbs l)]
where nbs :: [Int]
nbs = [0..]

View File

@ -2,20 +2,13 @@
{-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE ExistentialQuantification #-}
module KAT_AFIS (tests) where module KAT_AFIS (tests) where
import Control.Applicative import Imports
import Control.Monad
import Crypto.Hash import Crypto.Hash
import Crypto.Random import Crypto.Random
import qualified Crypto.Data.AFIS as AFIS import qualified Crypto.Data.AFIS as AFIS
import Data.ByteString.Char8 ()
import qualified Data.ByteString as B import qualified Data.ByteString as B
import Test.Tasty
import Test.Tasty.QuickCheck
import Test.Tasty.HUnit
mergeVec = mergeVec =
[ (3 [ (3
, hash :: HashFunctionBS SHA1 , hash :: HashFunctionBS SHA1

View File

@ -1,9 +1,8 @@
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
module KAT_Blowfish where module KAT_Blowfish where
--import Crypto.Cipher.Blowfish import Crypto.Cipher.Blowfish
--import Data.ByteString.Char8 () -- orphan IsString for older bytestring versions import Imports ()
import Imports
import BlockCipher import BlockCipher
vectors_ecb = -- key plaintext cipher vectors_ecb = -- key plaintext cipher
@ -43,12 +42,6 @@ vectors_ecb = -- key plaintext cipher
, KAT_ECB "\xFE\xDC\xBA\x98\x76\x54\x32\x10" "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" "\x6B\x5C\x5A\x9C\x5D\x9E\x0A\x5A" , KAT_ECB "\xFE\xDC\xBA\x98\x76\x54\x32\x10" "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" "\x6B\x5C\x5A\x9C\x5D\x9E\x0A\x5A"
] ]
{-
kats = defaultKATs { kat_ECB = vectors_ecb } kats = defaultKATs { kat_ECB = vectors_ecb }
main = defaultMain tests = testBlockCipher kats (undefined :: Blowfish64)
[ testBlockCipher kats (undefined :: Blowfish64)
]
-}
tests = testGroup "Blowfish" []

34
tests/KAT_Camellia.hs Normal file
View File

@ -0,0 +1,34 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ViewPatterns #-}
{-# OPTIONS_GHC -fno-warn-unused-binds #-}
{-# OPTIONS_GHC -fno-warn-unused-matches #-}
module KAT_Camellia (tests) where
import Imports ()
import BlockCipher
import qualified Data.ByteString as B
import Crypto.Cipher.Camellia
vectors_camellia128 =
[ KAT_ECB (B.replicate 16 0) (B.replicate 16 0) (B.pack [0x3d,0x02,0x80,0x25,0xb1,0x56,0x32,0x7c,0x17,0xf7,0x62,0xc1,0xf2,0xcb,0xca,0x71])
, KAT_ECB (B.pack [0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10])
(B.pack [0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10])
(B.pack [0x67,0x67,0x31,0x38,0x54,0x96,0x69,0x73,0x08,0x57,0x06,0x56,0x48,0xea,0xbe,0x43])
]
vectors_camellia192 =
[ KAT_ECB (B.pack [0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10,0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77]) (B.pack [0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10]) (B.pack [0xb4,0x99,0x34,0x01,0xb3,0xe9,0x96,0xf8,0x4e,0xe5,0xce,0xe7,0xd7,0x9b,0x09,0xb9])
]
vectors_camellia256 =
[ KAT_ECB (B.pack [0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10 ,0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff])
(B.pack [0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10])
(B.pack [0x9a,0xcc,0x23,0x7d,0xff,0x16,0xd7,0x6c,0x20,0xef,0x7c,0x91,0x9e,0x3a,0x75,0x09])
]
kats128 = defaultKATs { kat_ECB = vectors_camellia128 }
kats192 = defaultKATs { kat_ECB = vectors_camellia192 }
kats256 = defaultKATs { kat_ECB = vectors_camellia256 }
tests = testBlockCipher kats128 (undefined :: Camellia128)

49
tests/KAT_DES.hs Normal file
View File

@ -0,0 +1,49 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ViewPatterns #-}
module KAT_DES (tests) where
import Imports
import BlockCipher
import qualified Crypto.Cipher.DES as DES
vectors_ecb = -- key plaintext ciphertext
[ KAT_ECB "\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00" "\x8C\xA6\x4D\xE9\xC1\xB1\x23\xA7"
, KAT_ECB "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" "\x73\x59\xB2\x16\x3E\x4E\xDC\x58"
, KAT_ECB "\x30\x00\x00\x00\x00\x00\x00\x00" "\x10\x00\x00\x00\x00\x00\x00\x01" "\x95\x8E\x6E\x62\x7A\x05\x55\x7B"
, KAT_ECB "\x11\x11\x11\x11\x11\x11\x11\x11" "\x11\x11\x11\x11\x11\x11\x11\x11" "\xF4\x03\x79\xAB\x9E\x0E\xC5\x33"
, KAT_ECB "\x01\x23\x45\x67\x89\xAB\xCD\xEF" "\x11\x11\x11\x11\x11\x11\x11\x11" "\x17\x66\x8D\xFC\x72\x92\x53\x2D"
, KAT_ECB "\x11\x11\x11\x11\x11\x11\x11\x11" "\x01\x23\x45\x67\x89\xAB\xCD\xEF" "\x8A\x5A\xE1\xF8\x1A\xB8\xF2\xDD"
, KAT_ECB "\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00" "\x8C\xA6\x4D\xE9\xC1\xB1\x23\xA7"
, KAT_ECB "\xFE\xDC\xBA\x98\x76\x54\x32\x10" "\x01\x23\x45\x67\x89\xAB\xCD\xEF" "\xED\x39\xD9\x50\xFA\x74\xBC\xC4"
, KAT_ECB "\x7C\xA1\x10\x45\x4A\x1A\x6E\x57" "\x01\xA1\xD6\xD0\x39\x77\x67\x42" "\x69\x0F\x5B\x0D\x9A\x26\x93\x9B"
, KAT_ECB "\x01\x31\xD9\x61\x9D\xC1\x37\x6E" "\x5C\xD5\x4C\xA8\x3D\xEF\x57\xDA" "\x7A\x38\x9D\x10\x35\x4B\xD2\x71"
, KAT_ECB "\x07\xA1\x13\x3E\x4A\x0B\x26\x86" "\x02\x48\xD4\x38\x06\xF6\x71\x72" "\x86\x8E\xBB\x51\xCA\xB4\x59\x9A"
, KAT_ECB "\x38\x49\x67\x4C\x26\x02\x31\x9E" "\x51\x45\x4B\x58\x2D\xDF\x44\x0A" "\x71\x78\x87\x6E\x01\xF1\x9B\x2A"
, KAT_ECB "\x04\xB9\x15\xBA\x43\xFE\xB5\xB6" "\x42\xFD\x44\x30\x59\x57\x7F\xA2" "\xAF\x37\xFB\x42\x1F\x8C\x40\x95"
, KAT_ECB "\x01\x13\xB9\x70\xFD\x34\xF2\xCE" "\x05\x9B\x5E\x08\x51\xCF\x14\x3A" "\x86\xA5\x60\xF1\x0E\xC6\xD8\x5B"
, KAT_ECB "\x01\x70\xF1\x75\x46\x8F\xB5\xE6" "\x07\x56\xD8\xE0\x77\x47\x61\xD2" "\x0C\xD3\xDA\x02\x00\x21\xDC\x09"
, KAT_ECB "\x43\x29\x7F\xAD\x38\xE3\x73\xFE" "\x76\x25\x14\xB8\x29\xBF\x48\x6A" "\xEA\x67\x6B\x2C\xB7\xDB\x2B\x7A"
, KAT_ECB "\x07\xA7\x13\x70\x45\xDA\x2A\x16" "\x3B\xDD\x11\x90\x49\x37\x28\x02" "\xDF\xD6\x4A\x81\x5C\xAF\x1A\x0F"
, KAT_ECB "\x04\x68\x91\x04\xC2\xFD\x3B\x2F" "\x26\x95\x5F\x68\x35\xAF\x60\x9A" "\x5C\x51\x3C\x9C\x48\x86\xC0\x88"
, KAT_ECB "\x37\xD0\x6B\xB5\x16\xCB\x75\x46" "\x16\x4D\x5E\x40\x4F\x27\x52\x32" "\x0A\x2A\xEE\xAE\x3F\xF4\xAB\x77"
, KAT_ECB "\x1F\x08\x26\x0D\x1A\xC2\x46\x5E" "\x6B\x05\x6E\x18\x75\x9F\x5C\xCA" "\xEF\x1B\xF0\x3E\x5D\xFA\x57\x5A"
, KAT_ECB "\x58\x40\x23\x64\x1A\xBA\x61\x76" "\x00\x4B\xD6\xEF\x09\x17\x60\x62" "\x88\xBF\x0D\xB6\xD7\x0D\xEE\x56"
, KAT_ECB "\x02\x58\x16\x16\x46\x29\xB0\x07" "\x48\x0D\x39\x00\x6E\xE7\x62\xF2" "\xA1\xF9\x91\x55\x41\x02\x0B\x56"
, KAT_ECB "\x49\x79\x3E\xBC\x79\xB3\x25\x8F" "\x43\x75\x40\xC8\x69\x8F\x3C\xFA" "\x6F\xBF\x1C\xAF\xCF\xFD\x05\x56"
, KAT_ECB "\x4F\xB0\x5E\x15\x15\xAB\x73\xA7" "\x07\x2D\x43\xA0\x77\x07\x52\x92" "\x2F\x22\xE4\x9B\xAB\x7C\xA1\xAC"
, KAT_ECB "\x49\xE9\x5D\x6D\x4C\xA2\x29\xBF" "\x02\xFE\x55\x77\x81\x17\xF1\x2A" "\x5A\x6B\x61\x2C\xC2\x6C\xCE\x4A"
, KAT_ECB "\x01\x83\x10\xDC\x40\x9B\x26\xD6" "\x1D\x9D\x5C\x50\x18\xF7\x28\xC2" "\x5F\x4C\x03\x8E\xD1\x2B\x2E\x41"
, KAT_ECB "\x1C\x58\x7F\x1C\x13\x92\x4F\xEF" "\x30\x55\x32\x28\x6D\x6F\x29\x5A" "\x63\xFA\xC0\xD0\x34\xD9\xF7\x93"
, KAT_ECB "\x01\x01\x01\x01\x01\x01\x01\x01" "\x01\x23\x45\x67\x89\xAB\xCD\xEF" "\x61\x7B\x3A\x0C\xE8\xF0\x71\x00"
, KAT_ECB "\x1F\x1F\x1F\x1F\x0E\x0E\x0E\x0E" "\x01\x23\x45\x67\x89\xAB\xCD\xEF" "\xDB\x95\x86\x05\xF8\xC8\xC6\x06"
, KAT_ECB "\xE0\xFE\xE0\xFE\xF1\xFE\xF1\xFE" "\x01\x23\x45\x67\x89\xAB\xCD\xEF" "\xED\xBF\xD1\xC6\x6C\x29\xCC\xC7"
, KAT_ECB "\x00\x00\x00\x00\x00\x00\x00\x00" "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" "\x35\x55\x50\xB2\x15\x0E\x24\x51"
, KAT_ECB "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" "\x00\x00\x00\x00\x00\x00\x00\x00" "\xCA\xAA\xAF\x4D\xEA\xF1\xDB\xAE"
, KAT_ECB "\x01\x23\x45\x67\x89\xAB\xCD\xEF" "\x00\x00\x00\x00\x00\x00\x00\x00" "\xD5\xD4\x4F\xF7\x20\x68\x3D\x0D"
, KAT_ECB "\xFE\xDC\xBA\x98\x76\x54\x32\x10" "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" "\x2A\x2B\xB0\x08\xDF\x97\xC2\xF2"
]
kats = defaultKATs { kat_ECB = vectors_ecb }
tests = localOption (QuickCheckTests 5)
$ testBlockCipher kats (undefined :: DES.DES)

12
tests/KAT_TripleDES.hs Normal file
View File

@ -0,0 +1,12 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ViewPatterns #-}
module KAT_TripleDES (tests) where
import Imports
import BlockCipher
import qualified Crypto.Cipher.TripleDES as TripleDES
kats = defaultKATs
tests = localOption (QuickCheckTests 5)
$ testBlockCipher kats (undefined :: TripleDES.DES_EEE3)

View File

@ -1,14 +1,10 @@
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
module Main where module Main where
import Control.Applicative
import Data.Byteable import Data.Byteable
import Data.ByteString (ByteString)
import qualified Data.ByteString as B import qualified Data.ByteString as B
import Data.ByteString.Char8 ()
import Test.Tasty import Imports
import Test.Tasty.QuickCheck
import Test.Tasty.HUnit
import qualified Crypto.Cipher.ChaCha as ChaCha import qualified Crypto.Cipher.ChaCha as ChaCha
import qualified Crypto.Cipher.Salsa as Salsa import qualified Crypto.Cipher.Salsa as Salsa
@ -21,8 +17,11 @@ import qualified KAT_PBKDF2
import qualified KAT_Curve25519 import qualified KAT_Curve25519
import qualified KAT_PubKey import qualified KAT_PubKey
import qualified KAT_Scrypt import qualified KAT_Scrypt
import qualified KAT_RC4
import qualified KAT_Blowfish import qualified KAT_Blowfish
import qualified KAT_Camellia
import qualified KAT_DES
import qualified KAT_RC4
import qualified KAT_TripleDES
import qualified KAT_AFIS import qualified KAT_AFIS
b8_128_k0_i0 = "\xe2\x8a\x5f\xa4\xa6\x7f\x8c\x5d\xef\xed\x3e\x6f\xb7\x30\x34\x86\xaa\x84\x27\xd3\x14\x19\xa7\x29\x57\x2d\x77\x79\x53\x49\x11\x20\xb6\x4a\xb8\xe7\x2b\x8d\xeb\x85\xcd\x6a\xea\x7c\xb6\x08\x9a\x10\x18\x24\xbe\xeb\x08\x81\x4a\x42\x8a\xab\x1f\xa2\xc8\x16\x08\x1b\x8a\x26\xaf\x44\x8a\x1b\xa9\x06\x36\x8f\xd8\xc8\x38\x31\xc1\x8c\xec\x8c\xed\x81\x1a\x02\x8e\x67\x5b\x8d\x2b\xe8\xfc\xe0\x81\x16\x5c\xea\xe9\xf1\xd1\xb7\xa9\x75\x49\x77\x49\x48\x05\x69\xce\xb8\x3d\xe6\xa0\xa5\x87\xd4\x98\x4f\x19\x92\x5f\x5d\x33\x8e\x43\x0d" b8_128_k0_i0 = "\xe2\x8a\x5f\xa4\xa6\x7f\x8c\x5d\xef\xed\x3e\x6f\xb7\x30\x34\x86\xaa\x84\x27\xd3\x14\x19\xa7\x29\x57\x2d\x77\x79\x53\x49\x11\x20\xb6\x4a\xb8\xe7\x2b\x8d\xeb\x85\xcd\x6a\xea\x7c\xb6\x08\x9a\x10\x18\x24\xbe\xeb\x08\x81\x4a\x42\x8a\xab\x1f\xa2\xc8\x16\x08\x1b\x8a\x26\xaf\x44\x8a\x1b\xa9\x06\x36\x8f\xd8\xc8\x38\x31\xc1\x8c\xec\x8c\xed\x81\x1a\x02\x8e\x67\x5b\x8d\x2b\xe8\xfc\xe0\x81\x16\x5c\xea\xe9\xf1\xd1\xb7\xa9\x75\x49\x77\x49\x48\x05\x69\xce\xb8\x3d\xe6\xa0\xa5\x87\xd4\x98\x4f\x19\x92\x5f\x5d\x33\x8e\x43\x0d"
@ -81,8 +80,11 @@ tests = testGroup "cryptonite"
, KAT_PubKey.tests , KAT_PubKey.tests
, KAT_PBKDF2.tests , KAT_PBKDF2.tests
, KAT_Scrypt.tests , KAT_Scrypt.tests
, KAT_RC4.tests
, KAT_Blowfish.tests , KAT_Blowfish.tests
, KAT_Camellia.tests
, KAT_DES.tests
, KAT_RC4.tests
, KAT_TripleDES.tests
, KAT_AFIS.tests , KAT_AFIS.tests
] ]
where chachaRunSimple expected rounds klen nonceLen = where chachaRunSimple expected rounds klen nonceLen =