packages feed

ciphersaber2 (empty) → 0.1.0.0

raw patch · 7 files changed

+481/−0 lines, 7 filesdep +arraydep +basedep +bytestringsetup-changed

Dependencies added: array, base, bytestring, parseargs

Files

+ Data/CipherSaber2.hs view
@@ -0,0 +1,110 @@+-- Copyright © 2015 Bart Massey++-- | Implementation of the "CipherSaber-2" RC4 encryption+-- format. Also provides a raw RC4 keystream generator.+--+-- This work is licensed under the "MIT License".  Please+-- see the file LICENSE in the source distribution of this+-- software for license terms.+module Data.CipherSaber2 (+  ByteString, rc4, encrypt, decrypt,+  toByteString, fromByteString )+  where++import Control.Monad+import Control.Monad.ST.Safe+import Data.Array+import Data.Array.ST+import Data.Bits+import Data.ByteString (ByteString)+import qualified Data.ByteString as B+import qualified Data.ByteString.Char8 as BC+import Data.Word++-- | Number of bytes of IV to use in CipherSaber encryption/decryption+-- below. The standard CipherSaber IV size is 10 bytes.+ivLength :: Int+ivLength = 10++-- | Generate an RC4 keystream. CipherSaber recommends+-- a key of less than 54 bytes for best mixing. At most,+-- the first 256 bytes of the key are even used.+--+-- This function takes a parameter for the number of times+-- to repeat the key mixing loop ala "CipherSaber-2". It+-- should probably be set to at least 20.+-- +-- This function takes a length of keystream to generate,+-- which is un-Haskellike but hard to avoid given the+-- strictness of 'STUArray'. An alternative would be to pass+-- the plaintext in and combine it here, but this interface+-- was chosen as "simpler". Another choice would be to leave+-- whole rc4 function in the 'ST' monad, but that seemed+-- obnoxious. The performance and usability implications of+-- these choices need to be explored.+rc4 :: Int -> Int -> ByteString -> ByteString+rc4 scheduleReps keystreamLength key =+    B.pack $ runST $ do+      let nKey = fromIntegral $ B.length key :: Word8+      let key' = listArray (0, fromIntegral (nKey - 1)) $ B.unpack key ::+                 Array Word8 Word8+      -- Create and initialize the state.+      s <- newListArray (0, 255) [0..255] :: ST s (STUArray s Word8 Word8)+      -- One step of the key schedule+      let schedStep j i = do+            si <- readArray s i+            let keyByte = key' ! (i `mod` nKey)+            let j' = j + si + keyByte+            sj <- readArray s j'+            writeArray s i sj+            writeArray s j' si+            return j'+      -- Do the key scheduling.+      foldM_ schedStep 0 $ concat $ replicate scheduleReps [0..255]+      -- Do the keystream generation.+      let keystream 0 _ _ = return []+          keystream n i j = do+            let i' = i + 1+            si <- readArray s i'+            let j' = j + si+            sj <- readArray s j'+            writeArray s i' sj+            writeArray s j' si+            sk <- readArray s (si + sj)+            ks <- keystream (n - 1) i' j'+            return $ sk : ks+      -- Get the keystream.+      keystream keystreamLength 0 0++-- | Convert a 'String' to a 'ByteString'.+toByteString :: String -> ByteString+toByteString s = BC.pack s++-- | Convert a 'ByteString' to a 'String'.+fromByteString :: ByteString -> String+fromByteString bs = BC.unpack bs++-- | CipherSaber requires using a 10-byte initial value (IV)+-- to protect against keystream recovery. Given the key and+-- IV, this code will turn a a sequence of plaintext message+-- bytes into a sequence of ciphertext bytes.+encrypt :: Int -> ByteString -> ByteString -> ByteString -> ByteString+encrypt scheduleReps key iv plaintext+    | B.length iv == ivLength =+        let keystream = rc4 scheduleReps+                        (B.length plaintext)+                        (B.append key iv) in+        B.append iv $ B.pack $ B.zipWith xor keystream plaintext+    | otherwise = error $ "expected IV length " ++ show ivLength++-- | CipherSaber recovers the 10-byte IV from the start of the+-- ciphertext.  Given the key, this code will turn a+-- sequence of ciphertext bytes into a sequence of plaintext+-- bytes.+decrypt :: Int -> ByteString -> ByteString -> ByteString+decrypt scheduleReps key ciphertext0 =+    let (iv, ciphertext) = B.splitAt ivLength ciphertext0+        keystream = rc4 scheduleReps+                    (B.length ciphertext)+                    (B.append key iv) in+    B.pack $ B.zipWith xor keystream ciphertext
+ LICENSE view
@@ -0,0 +1,20 @@+Copyright (c) 2015 Bart Massey++Permission is hereby granted, free of charge, to any person obtaining+a copy of this software and associated documentation files (the+"Software"), to deal in the Software without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Software, and to+permit persons to whom the Software is furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ README.md view
@@ -0,0 +1,145 @@+# ciphersaber2+Copyright © 2015 Bart Massey++This package provides a Haskell library and driver program+implementing [CipherSaber-2](http://ciphersaber.gurus.org/)(CS2)+stream encryption based on the+[RC4](http://en.wikipedia.org/wiki/RC4) stream encryption+algorithm. This implementation has been tested against and+is compatible with existing CipherSaber implementations.++## CS2++The documentation for CS2 is a bit out-of-date and+scattered.++### History++CS2 is based on the RC4 stream cipher.  Wikipedia+has a nice+[history](http://en.wikipedia.org/wiki/RC4#History) of RC4+as well as current reports on its+[cryptanalysis](http://en.wikipedia.org/wiki/RC4#Security).++In 1999, Arnold Reinhold suggested using RC4 as the basis+for citizens to learn to build their own encryption+software, along the lines of Jedi Light Sabers. Reinhold+proposed a stream protocol for RC4 ciphertext that he called+[CipherSaber](http://ciphersaber.gurs.org) (Note that the CipherSaber+website is mostly abandoned and in some state of disrepair.)++In 2003, after cryptographic attacks were found against RC4+as used in CipherSaber, Reinhold modified the CipherSaber+protocol to produce a new parameterized family of protocols+known as CS2: the original CipherSaber is a+special case of CS2, and is often referred to as+CipherSaber-1.++### Algorithm++Pseudocode for CS2 is available from a variety of+places. The pseudocode given here attempts to be clear and+normative.++CS2 encryption and decryption both require an RC4+implementation that has been modified to iterate the key+schedule a given number of times.++<!-- This pseudocode translated from rc4.pseu by pseuf -->++>   +> --&nbsp;Produce an RC4 keystream of length&nbsp;*n*&nbsp;with  +> --&nbsp;*r*&nbsp;rounds of key scheduling given key&nbsp;*k*  +> *rc4*(*n*,&nbsp;*r*,&nbsp;*k*):  +> &nbsp;&nbsp;&nbsp;&nbsp;*l*&nbsp;&#8592;&nbsp;**length**&nbsp;*k*  +> &nbsp;&nbsp;&nbsp;&nbsp;--&nbsp;Initialize&nbsp;the&nbsp;array.  +> &nbsp;&nbsp;&nbsp;&nbsp;*S*&nbsp;&#8592;&nbsp;zero-based array of 256 bytes  +> &nbsp;&nbsp;&nbsp;&nbsp;**for**&nbsp;*i*&nbsp;**in**&nbsp;0..255  +> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*S*[*i*]&nbsp;&#8592;&nbsp;*i*  +> &nbsp;&nbsp;&nbsp;&nbsp;--&nbsp;Do&nbsp;key&nbsp;scheduling.  +> &nbsp;&nbsp;&nbsp;&nbsp;*j*&nbsp;&#8592;&nbsp;0  +> &nbsp;&nbsp;&nbsp;&nbsp;**repeat**&nbsp;*r*&nbsp;**times**  +> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**for**&nbsp;*i*&nbsp;**in**&nbsp;0..255  +> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*j*&nbsp;&#8592;&nbsp;(*j*&nbsp;+&nbsp;*S*[*i*]&nbsp;+&nbsp;*k*[*i*&nbsp;**mod**&nbsp;*l*])&nbsp;**mod**&nbsp;256  +> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*S*[*i*]&nbsp;<->&nbsp;*S*[*j*]  +> &nbsp;&nbsp;&nbsp;&nbsp;--&nbsp;Finally,&nbsp;produce&nbsp;the&nbsp;stream.  +> &nbsp;&nbsp;&nbsp;&nbsp;*keystream*&nbsp;&#8592;&nbsp;zero-based array of&nbsp;*n*&nbsp;bytes  +> &nbsp;&nbsp;&nbsp;&nbsp;*j*&nbsp;&#8592;&nbsp;0  +> &nbsp;&nbsp;&nbsp;&nbsp;**for**&nbsp;*i*&nbsp;**in**&nbsp;0..n-1  +> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i'&nbsp;&#8592;&nbsp;*i*&nbsp;**mod**&nbsp;256  +> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*j*&nbsp;&#8592;&nbsp;(*j*&nbsp;+&nbsp;*S*[i'])&nbsp;**mod**&nbsp;256  +> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*S*[i']&nbsp;<->&nbsp;*S*[*j*]  +> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*keystream*[*i*]&nbsp;&#8592;&nbsp;*S*[(*S*[i']&nbsp;+&nbsp;*S*[*j*])&nbsp;**mod**&nbsp;256]  +> &nbsp;&nbsp;&nbsp;&nbsp;**return**&nbsp;*keystream*  ++<!-- End of pseuf translation of rc4.pseu -->++CS2 encryption requires a plaintext message (treated as a+bytestream), a key with a recommended maximum size of 53+bytes and a required maximum size of 256 bytes, and an+"initial value"+([IV](http://en.wikipedia.org/wiki/Initialization_vector))+of 10 bytes. The IV is a+[nonce](http://en.wikipedia.org/wiki/Cryptographic_nonce)+that must be different for each message sent: it should be+chosen randomly if possible, but may be chosen+pseudo-randomly or even just counted if necessary.++<!-- This pseudocode translated from encrypt.pseu by pseuf -->++>   +> --&nbsp;Ciphersaber-2 encrypt message&nbsp;*m*&nbsp;with key&nbsp;*k*&nbsp;and  +> --&nbsp;*r*&nbsp;rounds of key scheduling  +> *encrypt*(*m*,&nbsp;*r*,&nbsp;*k*):  +> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*n*&nbsp;&#8592;&nbsp;**length**&nbsp;*m*  +> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*iv*&nbsp;&#8592;&nbsp;appropriately-chosen 10-byte IV  +> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;k'&nbsp;&#8592;&nbsp;prepend&nbsp;*k*&nbsp;**to**&nbsp;*iv*  +> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*keystream*&nbsp;&#8592;&nbsp;*rc4*(*n*,&nbsp;*r*,&nbsp;k')  +> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ciphertext&nbsp;&#8592;&nbsp;zero-based array of&nbsp;*n*&nbsp;+&nbsp;10&nbsp;bytes  +> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**for**&nbsp;*i*&nbsp;**in**&nbsp;0..9  +> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ciphertext[*i*]&nbsp;&#8592;&nbsp;*iv*[*i*]  +> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**for**&nbsp;*i*&nbsp;**in**&nbsp;0..*n*  +> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ciphertext[*i*&nbsp;+&nbsp;10]&nbsp;&#8592;&nbsp;*m*[*i*]&nbsp;**xor**&nbsp;*keystream*[*i*]  +> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**return**&nbsp;ciphertext  ++<!-- End of pseuf translation of encrypt.pseu -->++CS2 decryption requires ciphertext and the encryption key+used to produce the ciphertext.++<!-- This pseudocode translated from decrypt.pseu by pseuf -->++>   +> --&nbsp;Ciphersaber-2 decrypt ciphertext&nbsp;*m*&nbsp;with key&nbsp;*k*&nbsp;and  +> --&nbsp;*r*&nbsp;rounds of key scheduling  +> *decrypt*(*m*,&nbsp;*r*,&nbsp;*k*):  +> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*n*&nbsp;&#8592;&nbsp;**length**&nbsp;*m*  +> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*iv*&nbsp;&#8592;&nbsp;*m*[0..9]  +> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delete the first 10 characters of&nbsp;*m*  +> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;k'&nbsp;&#8592;&nbsp;prepend&nbsp;*k*&nbsp;**to**&nbsp;*iv*  +> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*keystream*&nbsp;&#8592;&nbsp;*rc4*(*n*&nbsp;-&nbsp;10,&nbsp;*r*,&nbsp;k')  +> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;plaintext&nbsp;&#8592;&nbsp;zero-based array of&nbsp;*n*&nbsp;-&nbsp;10&nbsp;bytes  +> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**for**&nbsp;*i*&nbsp;**in**&nbsp;0..n-10  +> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;plaintext[*i*]&nbsp;&#8592;&nbsp;*m*[*i*]&nbsp;**xor**&nbsp;*keystream*[*i*]  +> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**return**&nbsp;plaintext  ++<!-- End of pseuf translation of decrypt.pseu -->++## Library++The `CipherSaber2` library provides a relatively straightforward+`ByteString` interface. See the `haddock` documentation+for details.++## Driver++The program `cs2` uses the `CipherSaber2` library to encrypt+or decrypt `stdin` to `stdout`. Say "`cs2 --help`" for usage+information.++## License++This work is licensed under the "MIT License".  Please+see the file LICENSE in the source distribution of this+software for license terms.+
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ ciphersaber2.cabal view
@@ -0,0 +1,105 @@+-- Copyright © 2015 Bart Massey+-- This work is licensed under the "MIT License".  Please+-- see the file LICENSE in the source distribution of this+-- software for license terms.++-- Cabal file for ciphersaber2++-- The name of the package.+name:                ciphersaber2++-- The package version.  See the Haskell package versioning policy (PVP) +-- for standards guiding when and how versions should be incremented.+-- http://www.haskell.org/haskellwiki/Package_versioning_policy+-- PVP summary:      +-+------- breaking API changes+--                   | | +----- non-breaking API additions+--                   | | | +--- code changes with no API change+version:             0.1.0.0++-- A short (one-line) description of the package.+synopsis:            Implementation of CipherSaber2 RC4 cryptography.++-- A longer description of the package.+description:         This package implements CipherSaber-2, a+                     standard for RC4 encryption. See the+                     project website for details.++-- URL for the project homepage or repository.+homepage:            http://github.com/BartMassey/ciphersaber++-- The license under which the package is released.+license:             MIT++-- The file containing the license text.+license-file:        LICENSE++-- The package author(s).+author:              Bart Massey++-- An email address to which users can send suggestions, bug reports, and +-- patches.+maintainer:          bart@cs.pdx.edu++-- A copyright notice.+copyright:           Copyright © 2015 Bart Massey++category:            Data++build-type:          Simple++-- Extra files to be distributed with the package, such as examples or a +-- README.+extra-source-files:  README.md, test/README.md++-- Constraint on the version of Cabal needed to build this package.+cabal-version:       >=1.10++source-repository head+  type:     git+  location: http://github.com/BartMassey/ciphersaber2++source-repository this+  type:     git+  location: http://github.com/BartMassey/ciphersaber2+  tag:      v0.1.0.0++library+  -- Modules exported by the library.+  exposed-modules:     Data.CipherSaber2+  +  -- Modules included in this library but not exported.+  -- other-modules:       +  +  -- LANGUAGE extensions used by modules in this package.+  -- other-extensions:    +  +  -- Other library packages from which modules are imported.+  build-depends:       base >=4.7 && <5,+                       array >=0.5 && <1,+                       bytestring >= 0.10 && < 1+  +  -- Directories containing source files.+  -- hs-source-dirs:      +  +  -- Base language which the package is written in.+  default-language:    Haskell2010+  +  ghc-options: -Wall++executable cs2+  main-is: cs2.hs+  other-modules: Data.CipherSaber2++  -- Other library packages from which modules are imported.+  build-depends:       base >=4.7 && <5,+                       array >=0.5 && <1,+                       parseargs >= 0.1 && < 1,+                       bytestring >= 0.10 && < 1++  -- Directories containing source files.+  -- hs-source-dirs:++  -- Base language which the package is written in.+  default-language:    Haskell2010++  ghc-options: -Wall
+ cs2.hs view
@@ -0,0 +1,72 @@+-- Copyright © 2015 Bart Massey+-- [This work is licensed under the "MIT License"]+-- Please see the file LICENSE in the source+-- distribution of this software for license terms.++-- CipherSaber driver for UNIX-like systems with "/dev/random".++import Control.Monad+import qualified Data.ByteString.Char8 as BS+import Data.CipherSaber2+import System.Console.ParseArgs+import System.IO++data ArgInd = ArgEncrypt | ArgDecrypt | ArgKey | ArgReps+     deriving (Ord, Eq, Show)++argd :: [ Arg ArgInd ]+argd = [+  Arg {+     argIndex = ArgEncrypt,+     argName = Just "encrypt",+     argAbbr = Just 'e',+     argData = Nothing,+     argDesc = "Use decryption mode."+  },+  Arg {+     argIndex = ArgDecrypt,+     argName = Just "decrypt",+     argAbbr = Just 'd',+     argData = Nothing,+     argDesc = "Use encryption mode."+  },+  Arg {+     argIndex = ArgReps,+     argName = Just "reps",+     argAbbr = Just 'r',+     argData = argDataDefaulted "number" ArgtypeInt 20,+     argDesc = "Number of key scheduling reps " +++               "(use 1 for CipherSaber-1, default 20)."+  },+  Arg {+     argIndex = ArgKey,+     argName = Nothing,+     argAbbr = Nothing,+     argData = argDataRequired "key" ArgtypeString,+     argDesc = "Encryption or decryption key."+  } ]++makeIV :: IO BS.ByteString+makeIV = +  withBinaryFile "/dev/urandom" ReadMode $ \h ->+  do+    hSetBuffering h NoBuffering+    BS.hGet h 10++main :: IO ()+main = do+  hSetBinaryMode stdin True+  hSetBinaryMode stdout True+  argv <- parseArgsIO ArgsComplete argd+  let k = toByteString $ getRequiredArg argv ArgKey+  let e = gotArg argv ArgEncrypt+  let d = gotArg argv ArgDecrypt+  let r = getRequiredArg argv ArgReps :: Int+  unless ((e && not d) || (d && not e)) $+    usageError argv "Exactly one of -e or -d is required."+  case e of+    True -> do+      iv <- makeIV+      BS.interact (encrypt r k iv)+    False -> do+      BS.interact (decrypt r k)
+ test/README.md view
@@ -0,0 +1,27 @@+# Test Vectors for CipherSaber+Copyright &copy; 2015 Bart Massey++These test vectors are taken from the original+CipherSaber [documentation](http://ciphersaber.gurus.org/).++* `cstest1.cs1`: Plaintext "This is a test of CipherSaber."+  with no newline. Key "asdfg".++* `cstest2.cs1`: Plaintext of the Fourth Amendment to the+  U.S. Constitution. Key "SecretMessageforCongress" (note+  lowercase "f").++* `cknight.cs1`: Plaintext is GIF image of CipherKnight+  certificate. Key "ThomasJefferson". You must write your+  own CipherSaber implementation to claim this certificate.++* `cstest.cs2`: Plaintext "This is a test of CipherSaber-2."+  with no newline. Ten rounds of key scheduling. Key+  "asdfg".++[This website](http://www.cypherspace.org/adam/csvec/)+describes some human-memorable test vectors for+CipherSaber-2 with 20-round key scheduling and provides+software to generate more. My favorite is the ciphertext+input "Al Dakota guts" with key "Al", which corresponds+to the plaintext "held".