cipher-camellia-0.0.2/0000755000000000000000000000000012224676537012734 5ustar0000000000000000cipher-camellia-0.0.2/LICENSE0000644000000000000000000000272712224676537013751 0ustar0000000000000000Copyright (c) 2010-2013 Vincent Hanquez All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the author nor the names of his contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. cipher-camellia-0.0.2/cipher-camellia.cabal0000644000000000000000000000361012224676537016737 0ustar0000000000000000Name: cipher-camellia Version: 0.0.2 Description: Camellia block cipher primitives License: BSD3 License-file: LICENSE Copyright: Vincent Hanquez Author: Vincent Hanquez Maintainer: Vincent Hanquez Synopsis: Camellia block cipher primitives Category: Cryptography Build-Type: Simple Homepage: http://github.com/vincenthz/hs-crypto-cipher Cabal-Version: >=1.8 Library Build-Depends: base >= 4 && < 5 , bytestring , vector , byteable , securemem >= 0.1.2 , crypto-cipher-types >= 0.0.3 && < 0.1 Exposed-modules: Crypto.Cipher.Camellia Other-modules: Crypto.Cipher.Camellia.Primitive ghc-options: -Wall -fwarn-tabs Test-Suite test-cipher-camellia type: exitcode-stdio-1.0 hs-source-dirs: Tests Main-Is: Tests.hs Build-depends: base >= 4 && < 5 , bytestring , QuickCheck >= 2 , test-framework >= 0.3.3 , test-framework-quickcheck2 >= 0.2.9 , byteable , cipher-camellia , crypto-cipher-types , crypto-cipher-tests Benchmark bench-cipher-camellia hs-source-dirs: Benchmarks Main-Is: Benchmarks.hs type: exitcode-stdio-1.0 Build-depends: base >= 4 && < 5 , bytestring , criterion , mtl , cipher-camellia , crypto-cipher-types , crypto-cipher-benchmarks source-repository head type: git location: git://github.com/vincenthz/hs-crypto-cipher subdir: cipher-camellia cipher-camellia-0.0.2/Setup.hs0000644000000000000000000000005612224676537014371 0ustar0000000000000000import Distribution.Simple main = defaultMain cipher-camellia-0.0.2/Benchmarks/0000755000000000000000000000000012224676537015011 5ustar0000000000000000cipher-camellia-0.0.2/Benchmarks/Benchmarks.hs0000644000000000000000000000020512224676537017417 0ustar0000000000000000import Crypto.Cipher.Benchmarks import Crypto.Cipher.Camellia main = defaultMain [GBlockCipher (undefined :: Camellia128) ] cipher-camellia-0.0.2/Crypto/0000755000000000000000000000000012224676537014214 5ustar0000000000000000cipher-camellia-0.0.2/Crypto/Cipher/0000755000000000000000000000000012224676537015426 5ustar0000000000000000cipher-camellia-0.0.2/Crypto/Cipher/Camellia.hs0000644000000000000000000000146112224676537017473 0ustar0000000000000000-- | -- Module : Crypto.Cipher.Camellia -- License : BSD-style -- Maintainer : Vincent Hanquez -- 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 import Data.Byteable -- | Camellia block cipher with 128 bit key newtype Camellia128 = Camellia128 Camellia instance Cipher Camellia128 where cipherName _ = "Camellia128" cipherKeySize _ = KeySizeFixed 16 cipherInit k = either error Camellia128 $ initCamellia $ toBytes k instance BlockCipher Camellia128 where blockSize _ = 16 ecbEncrypt (Camellia128 key) = encrypt key ecbDecrypt (Camellia128 key) = decrypt key cipher-camellia-0.0.2/Crypto/Cipher/Camellia/0000755000000000000000000000000012224676537017135 5ustar0000000000000000cipher-camellia-0.0.2/Crypto/Cipher/Camellia/Primitive.hs0000644000000000000000000002730012224676537021443 0ustar0000000000000000-- | -- Module : Crypto.Cipher.Camellia.Primitive -- License : BSD-style -- Maintainer : Vincent Hanquez -- Stability : experimental -- Portability : Good -- -- this only cover Camellia 128 bits for now, API will change once -- 192 and 256 mode are implemented too module Crypto.Cipher.Camellia.Primitive ( Camellia , initCamellia , encrypt , decrypt ) where import Data.Word import Data.Vector.Unboxed import Data.Bits import qualified Data.ByteString as B import qualified Data.ByteString.Unsafe as B data Mode = Decrypt | Encrypt -- should probably use crypto large word ? data Word128 = Word128 !Word64 !Word64 deriving (Show, Eq) w128tow64 :: Word128 -> (Word64, Word64) w128tow64 (Word128 w1 w2) = (w1, w2) 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 w64tow32 :: Word64 -> (Word32, Word32) w64tow32 w = (fromIntegral (w `shiftR` 32), fromIntegral (w .&. 0xffffffff)) w32tow64 :: (Word32, Word32) -> Word64 w32tow64 (x1, x2) = ((fromIntegral x1) `shiftL` 32) .|. (fromIntegral x2) w128tow8 :: Word128 -> [Word8] w128tow8 (Word128 x1 x2) = [t1,t2,t3,t4,t5,t6,t7,t8,u1,u2,u3,u4,u5,u6,u7,u8] where (t1, t2, t3, t4, t5, t6, t7, t8) = w64tow8 x1 (u1, u2, u3, u4, u5, u6, u7, u8) = w64tow8 x2 getWord64 :: B.ByteString -> Word64 getWord64 s = sh 0 56 .|. sh 1 48 .|. sh 2 40 .|. sh 3 32 .|. sh 4 24 .|. sh 5 16 .|. sh 6 8 .|. sh 7 0 where sh i l = (fromIntegral (s `B.index` i) `shiftL` l) getWord128 :: B.ByteString -> Word128 getWord128 s = Word128 (getWord64 s) (getWord64 (B.drop 8 s)) putWord128 :: Word128 -> B.ByteString putWord128 = B.pack . w128tow8 sbox :: Vector Word8 sbox = fromList [112,130, 44,236,179, 39,192,229,228,133, 87, 53,234, 12,174, 65 , 35,239,107,147, 69, 25,165, 33,237, 14, 79, 78, 29,101,146,189 ,134,184,175,143,124,235, 31,206, 62, 48,220, 95, 94,197, 11, 26 ,166,225, 57,202,213, 71, 93, 61,217, 1, 90,214, 81, 86,108, 77 ,139, 13,154,102,251,204,176, 45,116, 18, 43, 32,240,177,132,153 ,223, 76,203,194, 52,126,118, 5,109,183,169, 49,209, 23, 4,215 , 20, 88, 58, 97,222, 27, 17, 28, 50, 15,156, 22, 83, 24,242, 34 ,254, 68,207,178,195,181,122,145, 36, 8,232,168, 96,252,105, 80 ,170,208,160,125,161,137, 98,151, 84, 91, 30,149,224,255,100,210 , 16,196, 0, 72,163,247,117,219,138, 3,230,218, 9, 63,221,148 ,135, 92,131, 2,205, 74,144, 51,115,103,246,243,157,127,191,226 , 82,155,216, 38,200, 55,198, 59,129,150,111, 75, 19,190, 99, 46 ,233,121,167,140,159,110,188,142, 41,245,249,182, 47,253,180, 89 ,120,152, 6,106,231, 70,113,186,212, 37,171, 66,136,162,141,250 ,114, 7,185, 85,248,238,172, 10, 54, 73, 42,104, 60, 56,241,164 , 64, 40,211,123,187,201, 67,193, 21,227,173,244,119,199,128,158 ] 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 :: Vector Word64 , kw :: Vector Word64 , ke :: Vector Word64 } setKeyInterim :: B.ByteString -> (Word128, Word128, Word128, Word128) setKeyInterim keyseed = (w64tow128 kL, w64tow128 kR, w64tow128 kA, w64tow128 kB) where kL = (w8tow64 $ B.take 8 keyseed, w8tow64 $ B.drop 8 keyseed) 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 :: B.ByteString -- ^ The seed to use when creating the key -> Either String Camellia initCamellia keyseed | B.length keyseed /= 16 = Left "wrong key size" | otherwise = let (kL, _, kA, _) = setKeyInterim keyseed in let (kw1, kw2) = w128tow64 (kL `rotl128` 0) in let (k1, k2) = w128tow64 (kA `rotl128` 0) in let (k3, k4) = w128tow64 (kL `rotl128` 15) in let (k5, k6) = w128tow64 (kA `rotl128` 15) in let (ke1, ke2) = w128tow64 (kA `rotl128` 30) in --ke1 = (KA <<< 30) >> 64; ke2 = (KA <<< 30) & MASK64; let (k7, k8) = w128tow64 (kL `rotl128` 45) in --k7 = (KL <<< 45) >> 64; k8 = (KL <<< 45) & MASK64; let (k9, _) = w128tow64 (kA `rotl128` 45) in --k9 = (KA <<< 45) >> 64; let (_, k10) = w128tow64 (kL `rotl128` 60) in let (k11, k12) = w128tow64 (kA `rotl128` 60) in let (ke3, ke4) = w128tow64 (kL `rotl128` 77) in let (k13, k14) = w128tow64 (kL `rotl128` 94) in let (k15, k16) = w128tow64 (kA `rotl128` 94) in let (k17, k18) = w128tow64 (kL `rotl128` 111) in let (kw3, kw4) = w128tow64 (kA `rotl128` 111) in Right $ Camellia { kw = fromList [ kw1, kw2, kw3, kw4 ] , ke = fromList [ ke1, ke2, ke3, ke4 ] , k = fromList [ 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) = w64tow32 fin in let (k1, k2) = w64tow32 sk in let y2 = x2 `xor` ((x1 .&. k1) `rotateL` 1) in let y1 = x1 `xor` (y2 .|. k2) in w32tow64 (y1, y2) flinv :: Word64 -> Word64 -> Word64 flinv fin sk = let (y1, y2) = w64tow32 fin in let (k1, k2) = w64tow32 sk in let x1 = y1 `xor` (y2 .|. k2) in let x2 = y2 `xor` ((x1 .&. k1) `rotateL` 1) in w32tow64 (x1, x2) {- in decrypt mode 0->17 1->16 ... -} getKeyK :: Mode -> Camellia -> Int -> Word64 getKeyK Encrypt key i = k key ! i getKeyK Decrypt key i = k key ! (17 - i) {- in decrypt mode 0->3 1->2 2->1 3->0 -} getKeyKe :: Mode -> Camellia -> Int -> Word64 getKeyKe Encrypt key i = ke key ! i getKeyKe Decrypt key i = ke key ! (3 - i) {- in decrypt mode 0->2 1->3 2->0 3->1 -} getKeyKw :: Mode -> Camellia -> Int -> Word64 getKeyKw Encrypt key i = kw key ! i getKeyKw Decrypt key i = kw key ! ((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 m = let (d1, d2) = w128tow64 m in 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 encryptChunk :: Camellia -> B.ByteString -> B.ByteString encryptChunk key b = putWord128 $ encryptBlock key $ getWord128 b decryptChunk :: Camellia -> B.ByteString -> B.ByteString decryptChunk key b = putWord128 $ decryptBlock key $ getWord128 b doChunks :: (B.ByteString -> B.ByteString) -> B.ByteString -> [B.ByteString] doChunks f b = let (x, rest) = B.splitAt 16 b in if B.length rest >= 16 then f x : doChunks f rest else [ f x ] -- | Encrypts the given ByteString using the given Key encrypt :: Camellia -- ^ The key to use -> B.ByteString -- ^ The data to encrypt -> B.ByteString encrypt key b = B.concat $ doChunks (encryptChunk key) b -- | Decrypts the given ByteString using the given Key decrypt :: Camellia -- ^ The key to use -> B.ByteString -- ^ The data to decrypt -> B.ByteString decrypt key b = B.concat $ doChunks (decryptChunk key) b cipher-camellia-0.0.2/Tests/0000755000000000000000000000000012224676537014036 5ustar0000000000000000cipher-camellia-0.0.2/Tests/Tests.hs0000644000000000000000000000412012224676537015471 0ustar0000000000000000{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ViewPatterns #-} module Main where import Control.Applicative import Control.Monad import Test.Framework (Test, defaultMain, testGroup) import Test.Framework.Providers.QuickCheck2 (testProperty) import Test.QuickCheck import Test.QuickCheck.Test import Data.Byteable import qualified Data.ByteString as B import Crypto.Cipher.Camellia import Crypto.Cipher.Types import Crypto.Cipher.Tests 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 } main = defaultMain [ testBlockCipher kats128 (undefined :: Camellia128) -- FIXME enable when Camellia 192 and 256 has been implemented --, testBlockCipher kats192 (undefined :: Camellia192) --, testBlockCipher kats256 (undefined :: Camellia256) ]