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 +110/−0
- LICENSE +20/−0
- README.md +145/−0
- Setup.hs +2/−0
- ciphersaber2.cabal +105/−0
- cs2.hs +72/−0
- test/README.md +27/−0
+ 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 -->++> +> -- Produce an RC4 keystream of length *n* with +> -- *r* rounds of key scheduling given key *k* +> *rc4*(*n*, *r*, *k*): +> *l* ← **length** *k* +> -- Initialize the array. +> *S* ← zero-based array of 256 bytes +> **for** *i* **in** 0..255 +> *S*[*i*] ← *i* +> -- Do key scheduling. +> *j* ← 0 +> **repeat** *r* **times** +> **for** *i* **in** 0..255 +> *j* ← (*j* + *S*[*i*] + *k*[*i* **mod** *l*]) **mod** 256 +> *S*[*i*] <-> *S*[*j*] +> -- Finally, produce the stream. +> *keystream* ← zero-based array of *n* bytes +> *j* ← 0 +> **for** *i* **in** 0..n-1 +> i' ← *i* **mod** 256 +> *j* ← (*j* + *S*[i']) **mod** 256 +> *S*[i'] <-> *S*[*j*] +> *keystream*[*i*] ← *S*[(*S*[i'] + *S*[*j*]) **mod** 256] +> **return** *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 -->++> +> -- Ciphersaber-2 encrypt message *m* with key *k* and +> -- *r* rounds of key scheduling +> *encrypt*(*m*, *r*, *k*): +> *n* ← **length** *m* +> *iv* ← appropriately-chosen 10-byte IV +> k' ← prepend *k* **to** *iv* +> *keystream* ← *rc4*(*n*, *r*, k') +> ciphertext ← zero-based array of *n* + 10 bytes +> **for** *i* **in** 0..9 +> ciphertext[*i*] ← *iv*[*i*] +> **for** *i* **in** 0..*n* +> ciphertext[*i* + 10] ← *m*[*i*] **xor** *keystream*[*i*] +> **return** 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 -->++> +> -- Ciphersaber-2 decrypt ciphertext *m* with key *k* and +> -- *r* rounds of key scheduling +> *decrypt*(*m*, *r*, *k*): +> *n* ← **length** *m* +> *iv* ← *m*[0..9] +> delete the first 10 characters of *m* +> k' ← prepend *k* **to** *iv* +> *keystream* ← *rc4*(*n* - 10, *r*, k') +> plaintext ← zero-based array of *n* - 10 bytes +> **for** *i* **in** 0..n-10 +> plaintext[*i*] ← *m*[*i*] **xor** *keystream*[*i*] +> **return** 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 © 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".