-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
1c460d3
commit f1065bf
Showing
5 changed files
with
105 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,99 @@ | ||
{-| | ||
Salsa20 Encryption and Decryption Application | ||
This Haskell program demonstrates the encryption and decryption of messages using the Salsa20 stream cipher. | ||
The application takes a user-provided secret key phrase and a message as input, performs encryption, | ||
and then decrypts the message to demonstrate the Salsa20 algorithm. | ||
The code uses the Salsa20 implementation from the hsalsa Crypt module, SHA256 for key hashing, Crypto.Nonce for | ||
nonce generation, and base64-bytestring for encoding. | ||
Based in https://asecuritysite.com/encryption/salsa20 | ||
-} | ||
module Main (main) where | ||
|
||
import Data.Word | ||
import Data.Char (ord) | ||
import qualified Data.ByteString | ||
import qualified Crypto.Hash.SHA256 as SHA256 | ||
import Crypto.Nonce | ||
import Data.ByteString.Base64 | ||
import Data.List.Split | ||
|
||
import Crypt | ||
|
||
main :: IO () | ||
main = do | ||
putStrLn "Salsa20 in haskell - Category theory" | ||
putStrLn "---Salsa20 encryption and decryption" | ||
putStrLn "" | ||
|
||
key <- getInput "Insert your secret key phrase:" | ||
message <- getInput "Insert message to be encrypted or decrypted:" | ||
|
||
printInfo ["", "Plain text: " ++ message, "Secret key: " ++ key] | ||
|
||
let messageBytes = intToWord32 $ stringToBytes message | ||
|
||
let keyHash = Data.ByteString.unpack $ SHA256.hash (Data.ByteString.pack (intToWord8 (stringToBytes key))) | ||
let keyB64 = Data.ByteString.Base64.encode $ Data.ByteString.pack keyHash | ||
|
||
printInfo ["Key used: " ++ byteStringtoCharList keyB64, "", "---Salsa20 Encrypt"] | ||
|
||
g <- Crypto.Nonce.new | ||
nonce <- Crypto.Nonce.nonce128 g | ||
|
||
let unpackedNonce = Data.ByteString.unpack nonce | ||
-- We just need half of the nonce so we split it in two and take the first half | ||
let nonces = Data.List.Split.chunksOf 8 unpackedNonce | ||
let nonceB64 = Data.ByteString.Base64.encode $ Data.ByteString.pack (head nonces) | ||
|
||
putStrLn ("Nonce: " ++ byteStringtoCharList nonceB64) | ||
|
||
-- Our API accepts 2 keys of 16 bytes each so we split the 32 bytes generated by the hash in two | ||
let keys = Data.List.Split.chunksOf 16 keyHash | ||
let key1 = keys!!0 | ||
let key2 = keys!!1 | ||
|
||
let nonceAsList = word8ToWord32 (head nonces) | ||
|
||
-- TODO: The API is ugly: | ||
-- - We should be able to pass the nonce, keys and message as a strings and the API should convert it? | ||
-- - The `0` at the end should not be needed? | ||
-- - etc | ||
let v2encrypted = cryptBlock32Compute messageBytes (word8ToWord32 key1) (word8ToWord32 key2) nonceAsList 0 | ||
|
||
let b64_cipher = Data.ByteString.Base64.encode $ Data.ByteString.pack (word32ToWord8 v2encrypted) | ||
printInfo ["Ciphertext: " ++ byteStringtoCharList b64_cipher, "", "---Salsa20 Decrypt"] | ||
|
||
let v2decrypted = cryptBlock32Compute v2encrypted (word8ToWord32 key1) (word8ToWord32 key2) nonceAsList 0 | ||
|
||
let b64_decrypted = Data.ByteString.pack (word32ToWord8 v2decrypted) | ||
|
||
putStrLn ("Decrypted: " ++ byteStringtoCharList b64_decrypted) | ||
|
||
return () | ||
|
||
where | ||
getInput prompt = do | ||
putStrLn prompt | ||
getLine | ||
|
||
printInfo = mapM_ putStrLn | ||
|
||
stringToBytes :: String -> [Int] | ||
stringToBytes = map ord | ||
|
||
intToWord32 :: [Int] -> [Word32] | ||
intToWord32 = map fromIntegral | ||
|
||
intToWord8 :: [Int] -> [Word8] | ||
intToWord8 = map fromIntegral | ||
|
||
byteStringtoCharList :: Data.ByteString.ByteString -> [Char] | ||
byteStringtoCharList = map (toEnum . fromEnum) . Data.ByteString.unpack | ||
|
||
word8ToWord32 :: [Word8] -> [Word32] | ||
word8ToWord32 = map fromIntegral | ||
|
||
word32ToWord8 :: [Word32] -> [Word8] | ||
word32ToWord8 = map fromIntegral |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters