RSA 1.2.0.0 → 1.2.1.0
raw patch · 3 files changed
+50/−48 lines, 3 filesdep +crypto-pubkey-typesdep ~taggedPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies added: crypto-pubkey-types
Dependency ranges changed: tagged
API changes (from Hackage documentation)
- Codec.Crypto.RSA: PrivateKey :: Int64 -> Integer -> Integer -> PrivateKey
- Codec.Crypto.RSA: PublicKey :: Int64 -> Integer -> Integer -> PublicKey
- Codec.Crypto.RSA: data PrivateKey
- Codec.Crypto.RSA: data PublicKey
- Codec.Crypto.RSA: instance Show PrivateKey
- Codec.Crypto.RSA: instance Show PublicKey
- Codec.Crypto.RSA: private_d :: PrivateKey -> Integer
- Codec.Crypto.RSA: private_n :: PrivateKey -> Integer
- Codec.Crypto.RSA: private_size :: PrivateKey -> Int64
- Codec.Crypto.RSA: public_e :: PublicKey -> Integer
- Codec.Crypto.RSA: public_n :: PublicKey -> Integer
- Codec.Crypto.RSA: public_size :: PublicKey -> Int64
Files
- Codec/Crypto/RSA.hs +43/−42
- RSA.cabal +3/−3
- Test.hs +4/−3
Codec/Crypto/RSA.hs view
@@ -4,8 +4,7 @@ -- RSA standard and RFC 3447. module Codec.Crypto.RSA( -- * Keys and key generations- PublicKey(..), PrivateKey(..)- , generateKeyPair+ generateKeyPair -- * High-level encryption and signing functions , encrypt , decrypt@@ -54,6 +53,7 @@ import Data.Int import Data.Word import Crypto.Random+import Crypto.Types.PubKey.RSA import Control.Monad.CryptoRandom #ifdef USE_BINARY@@ -66,27 +66,13 @@ import Data.Digest.Pure.MD5 #endif -data PublicKey = PublicKey { - public_size :: Int64 -- ^The size of the RSA modulus, in bytes.- , public_n :: Integer -- ^The RSA modulus.- , public_e :: Integer -- ^The public exponent.- }- deriving (Show)--data PrivateKey = PrivateKey {- private_size :: Int64 -- ^The size of the RSA modulus, in bytes.- , private_n :: Integer -- ^The RSA modulus.- , private_d :: Integer -- ^The private exponent.- }- deriving (Show)- #ifdef USE_BINARY instance Binary PublicKey where put pk = do putLazyByteString $ i2osp (public_size pk) 8 putLazyByteString $ i2osp (public_n pk) (public_size pk) get = do len <- (fromIntegral . os2ip) `fmap` getLazyByteString 8 n <- os2ip `fmap` getLazyByteString len- return $ PublicKey len n 65537 + return $ PublicKey (fromIntegral len) n 65537 instance Binary PrivateKey where put pk = do putLazyByteString $ i2osp (private_size pk) 8@@ -95,7 +81,14 @@ get = do len <- (fromIntegral . os2ip) `fmap` getLazyByteString 8 n <- os2ip `fmap` getLazyByteString len d <- os2ip `fmap` getLazyByteString len- return $ PrivateKey len n d + return $ PrivateKey { private_size = fromIntegral len+ , private_n = n+ , private_d = d+ , private_p = 0+ , private_q = 0+ , private_qinv = 0+ , private_dP = 0+ , private_dQ = 0 } #endif type HashFunction = ByteString -> ByteString@@ -122,7 +115,7 @@ -- generator is of considerable importance when using this function; the -- input CryptoRandomGen should never be used again for any other purpose. generateKeyPair :: CryptoRandomGen g => g -> Int -> (PublicKey, PrivateKey, g)-generateKeyPair g sizeBits = (PublicKey kLen n e, PrivateKey kLen n d, g')+generateKeyPair g sizeBits = (PublicKey kLen n e, privateKey, g') where kLen = fromIntegral $ sizeBits `div` 8 (p, q, g') = generate_pq g kLen@@ -130,6 +123,14 @@ phi = (p - 1) * (q - 1) e = 65537 d = modular_inverse e phi + privateKey = PrivateKey { private_size = kLen+ , private_n = n+ , private_d = d+ , private_p = 0+ , private_q = 0+ , private_qinv = 0+ , private_dP = 0+ , private_dQ = 0 } data EncryptionOptions = UseOAEP {@@ -189,14 +190,14 @@ encrypt' (UseOAEP hash mgf l) gen pub m = foldl enc1 (BS.empty, gen) chunks where hLen = BS.length $ hash BS.empty- chunkSize = public_size pub - (2 * hLen) - 2+ chunkSize = (fromIntegral $ public_size pub) - (2 * hLen) - 2 chunks = chunkify chunkSize m enc1 (!res, !g) !cur = let !(!newc,!g') = rsaes_oaep_encrypt g hash mgf pub l cur in (res `BS.append` newc, g') encrypt' UsePKCS1_v1_5 gen pub m = foldl enc1 (BS.empty, gen) chunks where chunkSize = public_size pub - 11- chunks = chunkify chunkSize m+ chunks = chunkify (fromIntegral chunkSize) m enc1 (!res, !g) !cur = let (!newc, g')=rsaes_pkcs1_v1_5_encrypt g pub cur in (res `BS.append` newc, g') @@ -206,7 +207,7 @@ decrypt' :: EncryptionOptions -> PrivateKey -> ByteString -> ByteString decrypt' opts priv cipher = BS.concat $ map decryptor chunks where- chunks = chunkify (private_size priv) cipher+ chunks = chunkify (fromIntegral $ private_size priv) cipher decryptor = case opts of UseOAEP hash mgf l -> rsaes_oaep_decrypt hash mgf priv l UsePKCS1_v1_5 -> rsaes_pkcs1_v1_5_decrypt priv@@ -243,7 +244,7 @@ where mLen = BS.length m -- Int64 hLen = BS.length $ hash BS.empty -- Int64- kLen = public_size k+ kLen = fromIntegral $ public_size k (seedStrict,g') = throwLeft $ genBytes (fromIntegral hLen) g seed = BS.fromChunks [seedStrict] -- Step 1@@ -260,7 +261,7 @@ -- Step 3 m_ip = os2ip em c_ip = rsa_ep (public_n k) (public_e k) m_ip- c = i2osp c_ip kLen+ c = i2osp c_ip (fromIntegral kLen) -- |The generalized implementation of RSAES-OAEP-DECRYPT. Again, 'decrypt' -- initializes this with a pretty good set of defaults if you don't understand@@ -295,8 +296,8 @@ hLen = BS.length $ hash BS.empty kLen = private_size k -- Step 1- bad_message_len = BS.length c /= kLen- bad_hash_len = kLen < ((2 * hLen) + 2)+ bad_message_len = BS.length c /= fromIntegral kLen+ bad_hash_len = fromIntegral kLen < ((2 * hLen) + 2) -- Step 2 c_ip = os2ip c m_ip = rsa_dp (private_n k) (private_d k) c_ip@@ -307,7 +308,7 @@ (maskedSeed, maskedDB) = BS.splitAt hLen msandmdb seedMask = mgf maskedDB hLen seed = maskedSeed `xorBS` seedMask- dbMask = mgf seed (kLen - hLen - 1)+ dbMask = mgf seed (fromIntegral kLen - hLen - 1) db = maskedDB `xorBS` dbMask (lHash', ps1m) = BS.splitAt hLen db one_m = BS.dropWhile (== 0) ps1m@@ -340,7 +341,7 @@ | message_too_long = error "message too long" | otherwise = (c, rGen') where- mLen = BS.length m+ mLen = fromIntegral $ BS.length m kLen = public_size k -- Step 1 message_too_long = mLen > (kLen - 11)@@ -366,7 +367,7 @@ | signal_error = error "decryption error" | otherwise = m where- mLen = BS.length c+ mLen = fromIntegral $ BS.length c kLen = private_size k -- Step 1 wrong_size = mLen /= kLen@@ -420,7 +421,7 @@ where kLen = public_size k -- Step 1- bad_size = BS.length s /= kLen+ bad_size = BS.length s /= fromIntegral kLen -- Step 2 s_i = os2ip s m_i = rsa_vp1 (public_n k) (public_e k) s_i@@ -439,8 +440,8 @@ -- 2^32 * hLen, where hLen is the passed length of the hash. generate_MGF1 :: HashFunction -> MGF generate_MGF1 hash mgfSeed maskLen - | BS.length mgfSeed > ((2 ^ (32::Int64)) * hLen) = error "mask too long"- | otherwise = loop BS.empty 0+ | BS.length mgfSeed > ((2 ^ (32::Int)) * hLen) = error "mask too long"+ | otherwise = loop BS.empty 0 where hLen = BS.length $ hash BS.empty end_counter = (maskLen `divCeil` hLen) - 1@@ -508,7 +509,7 @@ -- "i2osp converts a nonnegative integer to an octet string of a specified -- length" -- RFC 3447-i2osp :: Integral a => a -> Int64 -> ByteString+i2osp :: Integral a => a -> Int -> ByteString i2osp x len | isTooLarge = error "RSA internal error: integer too large" | otherwise = padding `BS.append` digits where@@ -517,7 +518,7 @@ xAsInt = fromIntegral x lenAsInt = fromIntegral len --- padding = BS.replicate (len - BS.length digits) 0+ padding = BS.replicate (fromIntegral len - BS.length digits) 0 digits = BS.pack $ reverse $ digits256 x digits256 v | v <= 255 = [fromIntegral v]@@ -549,15 +550,15 @@ | (s < 0) || (s >= n) = error "signature representative out of range" | otherwise = modular_exponentiation s e n -- (s ^ e) `mod` n -emsa_pkcs1_v1_5_encode :: HashInfo -> ByteString -> Int64 -> ByteString+emsa_pkcs1_v1_5_encode :: HashInfo -> ByteString -> Int -> ByteString emsa_pkcs1_v1_5_encode (HashInfo hash_ident hash) m emLen - | emLen < (tLen + 1) = error "intended encoded message length too short"- | otherwise = em+ | (fromIntegral emLen) < (tLen + 1) = error "intended encoded message length too short"+ | otherwise = em where h = hash m t = hash_ident `BS.append` h tLen = BS.length t- ps = BS.replicate (emLen - tLen - 3) 0xFF+ ps = BS.replicate (fromIntegral emLen - tLen - 3) 0xFF em = BS.concat [BS.singleton 0x00, BS.singleton 0x01, ps, BS.singleton 0x00, t] @@ -577,7 +578,7 @@ | BS.length bstr <= len = [bstr] | otherwise = (BS.take len bstr):(chunkify len $ BS.drop len bstr) -generate_random_bytestring :: CryptoRandomGen g => g -> Int64 -> (ByteString, g)+generate_random_bytestring :: CryptoRandomGen g => g -> Int -> (ByteString, g) generate_random_bytestring g 0 = (BS.empty, g) generate_random_bytestring g x = (BS.cons' first rest, g'') where@@ -592,7 +593,7 @@ -- Generate p and q. This is not necessarily the best way to do this, but the -- ANSI standard dealing with this cost money, and I was in a hurry.-generate_pq :: CryptoRandomGen g => g -> Int64 -> (Integer, Integer, g)+generate_pq :: CryptoRandomGen g => g -> Int -> (Integer, Integer, g) generate_pq g len | len < 2 = error "length to short for generate_pq" | p == q = generate_pq g'' len@@ -602,7 +603,7 @@ (baseQ, g'') = large_random_prime g' (len - (len `div` 2)) (p, q) = if baseP < baseQ then (baseQ, baseP) else (baseP, baseQ) -large_random_prime :: CryptoRandomGen g => g -> Int64 -> (Integer, g)+large_random_prime :: CryptoRandomGen g => g -> Int -> (Integer, g) large_random_prime g len = (prime, g''') where ([startH, startT], g') = random8s g 2@@ -611,7 +612,7 @@ start = os2ip $ BS.pack start_ls (prime, g''') = find_next_prime g'' start -random8s :: CryptoRandomGen g => g -> Int64 -> ([Word8], g)+random8s :: CryptoRandomGen g => g -> Int -> ([Word8], g) random8s g 0 = ([], g) random8s g x = let (rest, g') = random8s g (x - 1)
RSA.cabal view
@@ -1,6 +1,6 @@ name: RSA category: Cryptography, Codec-version: 1.2.0.0+version: 1.2.1.0 license: BSD3 license-file: LICENSE author: Adam Wick <awick@galois.com>@@ -32,7 +32,7 @@ Default: False Library- build-depends: bytestring, crypto-api >= 0.10, monadcryptorandom+ build-depends: bytestring, crypto-api >= 0.10, monadcryptorandom, crypto-pubkey-types GHC-Options: -O2 -Wall -fno-ignore-asserts -fno-warn-orphans if flag(OldBase) build-depends: base >= 3 && < 4, SHA < 1.4.1@@ -60,7 +60,7 @@ QuickCheck >= 2 && < 3, test-framework-quickcheck2 >= 0.2 && < 0.7, DRBG >= 0.2.3 && < 0.4,- tagged >= 0.2.3 && < 0.4+ tagged >= 0.2.3 && < 0.5 else Buildable: False GHC-Options: -O2 -Wall -fno-ignore-asserts -fno-warn-orphans
Test.hs view
@@ -10,6 +10,7 @@ import Crypto.Random import Crypto.Random.DRBG import Crypto.Types+import Crypto.Types.PubKey.RSA import Test.Framework (defaultMain, testGroup, Test) import Test.Framework.Providers.QuickCheck2 (testProperty)@@ -128,7 +129,7 @@ prop_i2o2i_identity (PI x) = x == (os2ip $ i2osp x 16) prop_o2i2o_identity :: NonEmptyByteString -> Bool-prop_o2i2o_identity (NEBS x) = x == (i2osp (os2ip x) (BS.length x))+prop_o2i2o_identity (NEBS x) = x == (i2osp (os2ip x) (fromIntegral $ BS.length x)) prop_ep_dp_identity :: KeyPair -> PositiveInteger -> Bool prop_ep_dp_identity (KP1K pub priv) (PI x) = m == m'@@ -160,14 +161,14 @@ kLen = public_size pub hLen = BS.length $ hash BS.empty mgf = generate_MGF1 hash- m = BS.take (kLen - (2 * hLen) - 2) x+ m = BS.take (fromIntegral kLen - (2 * hLen) - 2) x (c,_) = rsaes_oaep_encrypt g hash mgf pub l m m' = rsaes_oaep_decrypt hash mgf priv l c prop_pkcs_inverts :: CryptoRandomGen g => g -> KeyPair -> NonEmptyByteString -> Bool prop_pkcs_inverts g (KP1K pub priv) (NEBS x) = m == m' where- kLen = public_size pub+ kLen = fromIntegral $ public_size pub m = BS.take (kLen - 11) x (c,_) = rsaes_pkcs1_v1_5_encrypt g pub m m' = rsaes_pkcs1_v1_5_decrypt priv c