Permalink
Browse files

The BIGNUM type should not be exposed to users. Expose BigNum instead.

darcs-hash:20071029041210-62b54-68d35c265798f8f6a0fa499a283db508261e1750.gz
  • Loading branch information...
1 parent 3776e8c commit c0c99a5ea73dbd61d4143eb394925072f8461a7e @depressed-pho committed Oct 29, 2007
Showing with 131 additions and 77 deletions.
  1. +1 −1 Makefile
  2. +2 −1 NEWS
  3. +4 −9 OpenSSL.hsc
  4. +4 −4 OpenSSL/ASN1.hsc
  5. +64 −34 OpenSSL/BN.hsc
  6. +4 −4 OpenSSL/Cipher.hsc
  7. +28 −19 OpenSSL/DSA.hsc
  8. +20 −1 OpenSSL/EVP/PKey.hsc
  9. +2 −2 OpenSSL/RSA.hsc
  10. +1 −1 OpenSSL/Random.hsc
  11. +1 −1 tests/Cipher.hs
View
@@ -29,7 +29,7 @@ doc: .setup-config Setup
./Setup haddock
install: build
- ./Setup install
+ sudo ./Setup install
sdist: Setup
./Setup sdist
View
3 NEWS
@@ -1,10 +1,11 @@
Changes from 0.2 to [the next release]
--------------------------------------
-* Applied a patch by Adam Langley:
+* Applied patches by Adam Langley:
- tests/DSA.hs: Add a DSA test: this just adds a binary which tests
a few simple DSA cases (and runs a timing test) and prints "PASS"
as the last line of stdout in the case that everything looks good.
It doesn't include any hooks nor framework for running these.
+ - Bug fix for fast Integer<->BN functions
Changes from 0.1.1. to 0.2
View
@@ -11,9 +11,9 @@
-- [/TLS\/SSL network connection/] ssl(3) functionalities are
-- totally uncovered. They should be covered someday.
--
--- [/Low-level API to symmetric ciphers/] Only high-level APIs (EVP
--- and BIO) are available. But I believe no one will be lost without
--- functions like @DES_set_odd_parity@.
+-- [/Complete coverage of Low-level API to symmetric ciphers/] Only
+-- high-level APIs (EVP and BIO) are fully available. But I believe
+-- no one will be lost without functions like @DES_set_odd_parity@.
--
-- [/Low-level API to asymmetric ciphers/] Only a high-level API
-- (EVP) is available. But I believe no one will complain about the
@@ -25,14 +25,9 @@
-- [/X.509 v3 extension handling/] It should be supported in the
-- future.
--
--- [/HMAC message authentication/]
---
--- [/Low-level API to message digest functions/] Just use EVP or BIO
+-- [/Low-level API to message digest functions/] Just use EVP
-- instead of something like @MD5_Update@.
--
--- [/pseudo-random number generator/] rand(3) functionalities are
--- uncovered, but OpenSSL works very well by default.
---
-- [/API to PKCS\#12 functionality/] It should be covered someday.
--
-- [/BIO/] BIO isn't needed because we are Haskell hackers. Though
View
@@ -76,16 +76,16 @@ foreign import ccall unsafe "HsOpenSSL_M_ASN1_INTEGER_free"
_ASN1_INTEGER_free :: Ptr ASN1_INTEGER -> IO ()
foreign import ccall unsafe "ASN1_INTEGER_to_BN"
- _ASN1_INTEGER_to_BN :: Ptr ASN1_INTEGER -> BigNum -> IO BigNum
+ _ASN1_INTEGER_to_BN :: Ptr ASN1_INTEGER -> Ptr BIGNUM -> IO (Ptr BIGNUM)
foreign import ccall unsafe "BN_to_ASN1_INTEGER"
- _BN_to_ASN1_INTEGER :: BigNum -> Ptr ASN1_INTEGER -> IO (Ptr ASN1_INTEGER)
+ _BN_to_ASN1_INTEGER :: Ptr BIGNUM -> Ptr ASN1_INTEGER -> IO (Ptr ASN1_INTEGER)
peekASN1Integer :: Ptr ASN1_INTEGER -> IO Integer
peekASN1Integer intPtr
= allocaBN $ \ bn ->
- do _ASN1_INTEGER_to_BN intPtr bn
+ do _ASN1_INTEGER_to_BN intPtr (unwrapBN bn)
>>= failIfNull
peekBN bn
@@ -99,7 +99,7 @@ withASN1Integer :: Integer -> (Ptr ASN1_INTEGER -> IO a) -> IO a
withASN1Integer int m
= withBN int $ \ bn ->
allocaASN1Integer $ \ intPtr ->
- do _BN_to_ASN1_INTEGER bn intPtr
+ do _BN_to_ASN1_INTEGER (unwrapBN bn) intPtr
>>= failIfNull
m intPtr
View
@@ -1,20 +1,32 @@
#include "HsOpenSSL.h"
+-- #prune
+
+-- |BN - multiprecision integer arithmetics
+
module OpenSSL.BN
- ( BigNum
+ ( -- * Type
+ BigNum
, BIGNUM
+ -- * Allocation
, allocaBN
, withBN
- , peekBN
+
, newBN
+ , wrapBN -- private
+ , unwrapBN -- private
+ -- * Conversion from\/to Integer
+ , peekBN
#ifdef __GLASGOW_HASKELL__
, integerToBN
, bnToInteger
#endif
, integerToMPI
, mpiToInteger
+
+ -- * Computation
, modexp
-- * Random number generation
@@ -44,35 +56,47 @@ import GHC.Prim
import GHC.IOBase (IO(..))
#endif
-type BigNum = Ptr BIGNUM
-data BIGNUM = BIGNUM
+-- |'BigNum' is an opaque object representing a big number.
+newtype BigNum = BigNum (Ptr BIGNUM)
+data BIGNUM
foreign import ccall unsafe "BN_new"
- _new :: IO BigNum
+ _new :: IO (Ptr BIGNUM)
foreign import ccall unsafe "BN_free"
- _free :: BigNum -> IO ()
-
+ _free :: Ptr BIGNUM -> IO ()
+-- |@'allocaBN' f@ allocates a 'BigNum' and computes @f@. Then it
+-- frees the 'BigNum'.
allocaBN :: (BigNum -> IO a) -> IO a
allocaBN m
- = bracket _new _free m
+ = bracket _new _free (m . wrapBN)
+
+
+unwrapBN :: BigNum -> Ptr BIGNUM
+unwrapBN (BigNum p) = p
+
+
+wrapBN :: Ptr BIGNUM -> BigNum
+wrapBN = BigNum
#ifndef __GLASGOW_HASKELL__
{- slow, safe functions ----------------------------------------------------- -}
foreign import ccall unsafe "BN_bn2dec"
- _bn2dec :: BigNum -> IO CString
+ _bn2dec :: Ptr BIGNUM -> IO CString
foreign import ccall unsafe "BN_dec2bn"
- _dec2bn :: Ptr BigNum -> CString -> IO Int
+ _dec2bn :: Ptr (Ptr BIGNUM) -> CString -> IO Int
foreign import ccall unsafe "HsOpenSSL_OPENSSL_free"
_openssl_free :: Ptr a -> IO ()
+-- |@'withBN' n f@ converts n to a 'BigNum' and computes @f@. Then it
+-- frees the 'BigNum'.
withBN :: Integer -> (BigNum -> IO a) -> IO a
withBN dec m
= withCString (show dec) $ \ strPtr ->
@@ -82,7 +106,7 @@ withBN dec m
>>= failIf (== 0)
bracket (peek bnPtr) _free m
-
+-- |@'peekBN' bn@ converts a 'BigNum' to an 'Prelude.Integer'.
peekBN :: BigNum -> IO Integer
peekBN bn
= do strPtr <- _bn2dec bn
@@ -138,11 +162,11 @@ freezeByteArray arr = IO $ \s ->
-- | Convert a BIGNUM to an Integer
bnToInteger :: BigNum -> IO Integer
bnToInteger bn = do
- nlimbs <- (#peek BIGNUM, top) bn :: IO CSize
+ nlimbs <- (#peek BIGNUM, top) (unwrapBN bn) :: IO CSize
case nlimbs of
0 -> return 0
- 1 -> do (I## i) <- (#peek BIGNUM, d) bn >>= peek
- negative <- (#peek BIGNUM, neg) bn :: IO Word32
+ 1 -> do (I## i) <- (#peek BIGNUM, d) (unwrapBN bn) >>= peek
+ negative <- (#peek BIGNUM, neg) (unwrapBN bn) :: IO Word32
if negative == 0
then return $ S## i
else return $ 0 - (S## i)
@@ -151,9 +175,9 @@ bnToInteger bn = do
(I## limbsize) = (#size unsigned long)
(MBA arr) <- newByteArray (nlimbsi *## limbsize)
(BA ba) <- freezeByteArray arr
- limbs <- (#peek BIGNUM, d) bn
+ limbs <- (#peek BIGNUM, d) (unwrapBN bn)
_copy_in ba limbs $ fromIntegral $ nlimbs * (#size unsigned long)
- negative <- (#peek BIGNUM, neg) bn :: IO Word32
+ negative <- (#peek BIGNUM, neg) (unwrapBN bn) :: IO Word32
if negative == 0
then return $ J## nlimbsi ba
else return $ 0 - (J## nlimbsi ba)
@@ -173,7 +197,7 @@ integerToBN 0 = do
(#poke BIGNUM, top) bnptr zero
(#poke BIGNUM, dmax) bnptr zero
(#poke BIGNUM, neg) bnptr zero
- return bnptr
+ return (wrapBN bnptr)
integerToBN (S## v) = do
bnptr <- mallocBytes (#size BIGNUM)
@@ -188,7 +212,7 @@ integerToBN (S## v) = do
(#poke BIGNUM, top) bnptr one
(#poke BIGNUM, dmax) bnptr one
(#poke BIGNUM, neg) bnptr (if (I## v) < 0 then one else 0)
- return bnptr
+ return (wrapBN bnptr)
integerToBN v@(J## nlimbs_ bytearray)
| v >= 0 = do
@@ -201,29 +225,34 @@ integerToBN v@(J## nlimbs_ bytearray)
(#poke BIGNUM, top) bnptr ((fromIntegral nlimbs) :: Word32)
(#poke BIGNUM, dmax) bnptr ((fromIntegral nlimbs) :: Word32)
(#poke BIGNUM, neg) bnptr (0 :: Word32)
- return bnptr
+ return (wrapBN bnptr)
| otherwise = do bnptr <- integerToBN (0-v)
- (#poke BIGNUM, neg) bnptr (1 :: Word32)
+ (#poke BIGNUM, neg) (unwrapBN bnptr) (1 :: Word32)
return bnptr
-- TODO: we could make a function which doesn't even allocate BN data if we
-- wanted to be very fast and dangerout. The BIGNUM could point right into the
-- Integer's data. However, I'm not sure about the semantics of the GC; which
-- might move the Integer data around.
+-- |@'withBN' n f@ converts n to a 'BigNum' and computes @f@. Then it
+-- frees the 'BigNum'.
withBN :: Integer -> (BigNum -> IO a) -> IO a
-withBN dec m = bracket (integerToBN dec) _free m
+withBN dec m = bracket (integerToBN dec) (_free . unwrapBN) m
+-- |This is an alias to 'bnToInteger'.
peekBN :: BigNum -> IO Integer
peekBN = bnToInteger
+-- |This is an alias to 'integerToBN'.
+newBN :: Integer -> IO BigNum
newBN = integerToBN
foreign import ccall unsafe "BN_bn2mpi"
- _bn2mpi :: BigNum -> Ptr CChar -> IO CInt
+ _bn2mpi :: Ptr BIGNUM -> Ptr CChar -> IO CInt
foreign import ccall unsafe "BN_mpi2bn"
- _mpi2bn :: Ptr CChar -> CInt -> BigNum -> IO BigNum
+ _mpi2bn :: Ptr CChar -> CInt -> Ptr BIGNUM -> IO (Ptr BIGNUM)
#endif
@@ -232,31 +261,31 @@ foreign import ccall unsafe "BN_mpi2bn"
-- most-significant-first order.
bnToMPI :: BigNum -> IO BS.ByteString
bnToMPI bn = do
- bytes <- _bn2mpi bn nullPtr
+ bytes <- _bn2mpi (unwrapBN bn) nullPtr
allocaBytes (fromIntegral bytes) (\buffer -> do
- _bn2mpi bn buffer
+ _bn2mpi (unwrapBN bn) buffer
BS.copyCStringLen (buffer, fromIntegral bytes))
-- | Convert an MPI into a BigNum. See bnToMPI for details of the format
mpiToBN :: BS.ByteString -> IO BigNum
mpiToBN mpi = do
BS.useAsCStringLen mpi (\(ptr, len) -> do
- _mpi2bn ptr (fromIntegral len) nullPtr)
+ _mpi2bn ptr (fromIntegral len) nullPtr) >>= return . wrapBN
-- | Convert an Integer to an MPI. SEe bnToMPI for the format
integerToMPI :: Integer -> IO BS.ByteString
-integerToMPI v = bracket (integerToBN v) _free bnToMPI
+integerToMPI v = bracket (integerToBN v) (_free . unwrapBN) bnToMPI
-- | Convert an MPI to an Integer. SEe bnToMPI for the format
mpiToInteger :: BS.ByteString -> IO Integer
mpiToInteger mpi = do
bn <- mpiToBN mpi
v <- bnToInteger bn
- _free bn
+ _free (unwrapBN bn)
return v
foreign import ccall unsafe "BN_mod_exp"
- _mod_exp :: BigNum -> BigNum -> BigNum -> BigNum -> BNCtx -> IO BigNum
+ _mod_exp :: Ptr BIGNUM -> Ptr BIGNUM -> Ptr BIGNUM -> Ptr BIGNUM -> BNCtx -> IO (Ptr BIGNUM)
type BNCtx = Ptr BNCTX
data BNCTX = BNCTX
@@ -270,23 +299,24 @@ foreign import ccall unsafe "BN_CTX_free"
withBNCtx :: (BNCtx -> IO a) -> IO a
withBNCtx f = bracket _BN_ctx_new _BN_ctx_free f
+-- |@'modexp' a p m@ computes @a@ to the @p@-th power modulo @m@.
modexp :: Integer -> Integer -> Integer -> Integer
modexp a p m = unsafePerformIO (do
withBN a (\bnA -> (do
withBN p (\bnP -> (do
withBN m (\bnM -> (do
withBNCtx (\ctx -> (do
r <- newBN 0
- _mod_exp r bnA bnP bnM ctx
+ _mod_exp (unwrapBN r) (unwrapBN bnA) (unwrapBN bnP) (unwrapBN bnM) ctx
bnToInteger r >>= return)))))))))
{- Random Integer generation ------------------------------------------------ -}
foreign import ccall unsafe "BN_rand_range"
- _BN_rand_range :: BigNum -> BigNum -> IO CInt
+ _BN_rand_range :: Ptr BIGNUM -> Ptr BIGNUM -> IO CInt
foreign import ccall unsafe "BN_pseudo_rand_range"
- _BN_pseudo_rand_range :: BigNum -> BigNum -> IO CInt
+ _BN_pseudo_rand_range :: Ptr BIGNUM -> Ptr BIGNUM -> IO CInt
-- | Return a strongly random number in the range 0 <= x < n where the given
-- filter function returns true.
@@ -296,7 +326,7 @@ randIntegerUptoNMinusOneSuchThat :: (Integer -> Bool) -- ^ a filter function
randIntegerUptoNMinusOneSuchThat f range = withBN range (\bnRange -> (do
r <- newBN 0
let try = do
- _BN_rand_range r bnRange >>= failIf (/= 1)
+ _BN_rand_range (unwrapBN r) (unwrapBN bnRange) >>= failIf (/= 1)
i <- bnToInteger r
if f i
then return i
@@ -311,7 +341,7 @@ prandIntegerUptoNMinusOneSuchThat :: (Integer -> Bool) -- ^ a filter function
prandIntegerUptoNMinusOneSuchThat f range = withBN range (\bnRange -> (do
r <- newBN 0
let try = do
- _BN_rand_range r bnRange >>= failIf (/= 1)
+ _BN_rand_range (unwrapBN r) (unwrapBN bnRange) >>= failIf (/= 1)
i <- bnToInteger r
if f i
then return i
View
@@ -34,10 +34,10 @@ modeToInt Decrypt = 0
data AES_KEY
data AESCtx = AESCtx
- (ForeignPtr AES_KEY) -- ^ the key schedule
- (ForeignPtr CUChar) -- ^ the IV / counter
- (ForeignPtr CUChar) -- ^ the encrypted counter (CTR mode)
- (IORef CUInt) -- ^ the number of bytes of the encrypted counter used
+ (ForeignPtr AES_KEY) -- the key schedule
+ (ForeignPtr CUChar) -- the IV / counter
+ (ForeignPtr CUChar) -- the encrypted counter (CTR mode)
+ (IORef CUInt) -- the number of bytes of the encrypted counter used
Mode
foreign import ccall unsafe "memcpy"
Oops, something went wrong.

0 comments on commit c0c99a5

Please sign in to comment.