Skip to content

Instantly share code, notes, and snippets.

@rnons
Created June 5, 2014 02:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rnons/3d952c60549f9424feb2 to your computer and use it in GitHub Desktop.
Save rnons/3d952c60549f9424feb2 to your computer and use it in GitHub Desktop.
HsOpenSSL cipher result different from OpenSSL?
/*
* Run with
* gcc -o cipher cipher.c -lcrypto
* ./cipher
*/
#include <string.h>
#include <openssl/evp.h>
int main()
{
EVP_CIPHER_CTX ctx;
EVP_CIPHER *method;
char out[1024];
char key[] = "\x90\x01\x50\x98\x3c\xd2\x4f\xb0\xd6\x96\x3f\x7d\x28\xe1\x7f\x72";
char iv[] = "\xcc\x88\xa5\x26\x85\xaf\x7f\x8d";
char str[] = "abcd";
int i;
OpenSSL_add_all_ciphers();
method = EVP_get_cipherbyname("bf-cfb");
EVP_CipherInit(&ctx, method, key, iv, 1);
EVP_CipherUpdate(&ctx, out, &i, str, strlen(str));
out[i] = 0;
printf("%s\n", out);
}
-- Scrapped from https://github.com/phonohawk/HsOpenSSL
-- Run with
-- hsc2hs cipher.hsc
-- ghci cipher.hs -lcrypto -lssl
-- main
--
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE ForeignFunctionInterface #-}
#include <openssl/evp.h>
import Control.Applicative ((<$>))
import Control.Exception (mask_)
import qualified Data.ByteString.Internal as B8
import qualified Data.ByteString.Unsafe as B8
import Data.Maybe (fromJust)
import Foreign.C
import Foreign.C.Types
import Foreign.ForeignPtr
import Foreign.Marshal.Alloc (alloca)
import Foreign.Ptr
import Foreign.Storable (Storable(..))
foreign import ccall unsafe "EVP_CIPHER_CTX_init"
_cipher_ctx_init :: Ptr EVP_CIPHER_CTX -> IO ()
foreign import ccall unsafe "&EVP_CIPHER_CTX_cleanup"
_cipher_ctx_cleanup :: FunPtr (Ptr EVP_CIPHER_CTX -> IO ())
foreign import ccall unsafe "EVP_CIPHER_CTX_block_size"
_cipher_ctx_block_size :: Ptr EVP_CIPHER_CTX -> CInt
foreign import ccall unsafe "OpenSSL_add_all_ciphers"
addAllCiphers :: IO ()
foreign import ccall unsafe "EVP_get_cipherbyname"
_get_cipherbyname :: CString -> IO (Ptr EVP_CIPHER)
foreign import ccall unsafe "EVP_CipherInit"
_CipherInit :: Ptr EVP_CIPHER_CTX -> Ptr EVP_CIPHER -> CString -> CString -> CInt -> IO CInt
foreign import ccall unsafe "EVP_CipherUpdate"
_CipherUpdate :: Ptr EVP_CIPHER_CTX -> Ptr CChar -> Ptr CInt
-> Ptr CChar -> CInt -> IO CInt
newtype Cipher = Cipher (Ptr EVP_CIPHER)
data EVP_CIPHER
newtype CipherCtx = CipherCtx (ForeignPtr EVP_CIPHER_CTX)
data EVP_CIPHER_CTX
newCipherCtx :: IO CipherCtx
newCipherCtx = do
ctx <- mallocForeignPtrBytes (#size EVP_CIPHER_CTX)
mask_ $ do
withForeignPtr ctx _cipher_ctx_init
addForeignPtrFinalizer _cipher_ctx_cleanup ctx
return $ CipherCtx ctx
withCipherCtxPtr :: CipherCtx -> (Ptr EVP_CIPHER_CTX -> IO a) -> IO a
withCipherCtxPtr (CipherCtx ctx) = withForeignPtr ctx
-- |@'getCipherByName' name@ returns a symmetric cipher algorithm
-- whose name is @name@. If no algorithms are found, the result is
-- @Nothing@.
getCipherByName :: String -> IO (Maybe Cipher)
getCipherByName name
= withCString name $ \ namePtr ->
do ptr <- _get_cipherbyname namePtr
if ptr == nullPtr then
return Nothing
else
return $ Just $ Cipher ptr
data CryptoMode = Encrypt | Decrypt
cryptoModeToInt :: CryptoMode -> CInt
cryptoModeToInt Encrypt = 1
cryptoModeToInt Decrypt = 0
cipherInit :: Cipher -> String -> String -> CryptoMode -> IO CipherCtx
cipherInit (Cipher c) key iv mode
= do ctx <- newCipherCtx
withCipherCtxPtr ctx $ \ ctxPtr ->
withCString key $ \ keyPtr ->
withCString iv $ \ ivPtr ->
_CipherInit ctxPtr c keyPtr ivPtr (cryptoModeToInt mode)
>>= failIf_ (/= 1)
return ctx
cipherUpdateBS :: CipherCtx -> B8.ByteString -> IO B8.ByteString
cipherUpdateBS ctx inBS =
withCipherCtxPtr ctx $ \ctxPtr ->
B8.unsafeUseAsCStringLen inBS $ \(inBuf, inLen) ->
let len = inLen + fromIntegral (_cipher_ctx_block_size ctxPtr) - 1 in
B8.createAndTrim len $ \outBuf ->
alloca $ \outLenPtr ->
_CipherUpdate ctxPtr (castPtr outBuf) outLenPtr inBuf
(fromIntegral inLen)
>>= failIf (/= 1)
>> fromIntegral <$> peek outLenPtr
failIf :: (a -> Bool) -> a -> IO a
failIf f a
| f a = error "error"
| otherwise = return a
failIf_ :: (a -> Bool) -> a -> IO ()
failIf_ f a
= failIf f a >> return ()
main :: IO ()
main = do
addAllCiphers
method <- fmap fromJust $ getCipherByName "bf-cfb"
ctx <- cipherInit method "\x90\x01\x50\x98\x3c\xd2\x4f\xb0\xd6\x96\x3f\x7d\x28\xe1\x7f\x72" "\xcc\x88\xa5\x26\x85\xaf\x7f\x8d" Encrypt
ciphered <- cipherUpdateBS ctx "abcd"
print ciphered
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment