galoisinc / rsa Goto Github PK
View Code? Open in Web Editor NEWHaskell RSA Library
License: Other
Haskell RSA Library
License: Other
Hi, i'm planning to update the private key RSA structure with the following patch:
- { private_size :: Int -- ^ size of key in bytes
- , private_n :: Integer -- ^ private p*q
+ { private_pub :: PublicKey -- ^ public part of a private key (size, n and e)
This makes the public key a sub field of a private key, instead of having 2 duplicate fields (private_n and private_size). In this case, e is useful for doing crypto-blinding when using chinese remainder optimisations.
is this update acceptable for RSA ? if so i'll do a pull request, otherwise i'm willing to discuss other possible solutions.
RSA 2.3.1 does not work with GHC 8.8.1, viz.
Failed to build RSA-2.3.1.
Build log (
/home/vanessa/.cabal/logs/ghc-8.8.1/RSA-2.3.1-c59e8e4482141f5af242e6d9c4033702e38dc4542988b1a987b598e39b2af471.log
):
Configuring library for RSA-2.3.1..
Preprocessing library for RSA-2.3.1..
Building library for RSA-2.3.1..
[1 of 3] Compiling Codec.Crypto.RSA.Pure ( src/Codec/Crypto/RSA/Pure.hs, dist/build/Codec/Crypto/RSA/Pure.o )
src/Codec/Crypto/RSA/Pure.hs:115:25: error:
• Could not deduce (MonadFail m) arising from a use of ‘fail’
from the context: (Monad m, Show a)
bound by the type signature for:
failOnError :: forall (m :: * -> *) a b.
(Monad m, Show a) =>
Either a b -> m b
at src/Codec/Crypto/RSA/Pure.hs:114:1-53
Possible fix:
add (MonadFail m) to the context of
the type signature for:
failOnError :: forall (m :: * -> *) a b.
(Monad m, Show a) =>
Either a b -> m b
• In the expression: fail (show e)
In an equation for ‘failOnError’:
failOnError (Left e) = fail (show e)
|
115 | failOnError (Left e) = fail (show e)
| ^^^^^^^^^^^^^
cabal: Failed to build RSA-2.3.1 (which is required by exe:tweet from
tweet-hs-1.0.2.1). See the build log above for details.
In light of http://tab.snarc.org/posts/haskell/2015-06-02-announcing_cryptonite.html the "crypto-pubkey-types" dependency is not long for the world, so this package should probably move over to the newer cryptonite. That also probably means shucking crypto-api's Crypto.Random in favor of cryptonite API, though I don't believe it's essential.
The core modules (src/Codec/Crypto/RSA/Exceptions.hs and src/Codec/Crypto/RSA/Pure.hs) seem easily enough moved, but the test harness (Test.hs) is a little more involved.
That said, cryptonite packages its own RSA implementation, so perhaps anything relevant from this package should go upstream there and this should be deprecated?
Thanks!
This version of bytestring is shipped with GHC 9.8.
The constraint stems from the library and test-suite components:
Line 24 in 28ab319
Recent RSA stopped exporting the PublicKey
constructor.
I use it to create a RSA public key from pre-known parameters, for instance, DKIM information on DNS. It seems to me there is no API to create PublicKey except generating a key pair.
I would like to re-export PublicKey
or provide APIs to create a public key.
The same discussion should be applied to a secret key.
I was testing PKCS#1 v1.5 signature verification as implemented in RSA package and noticed it rejects valid signature whose encoded message uses an implicit NULL parameter for hash algorithm (where digestAlgorithm ANS.1 der encoded does not have NULL parameter TLV; that is, 0x0500
is absent).
According to RFC4055, pg.5 and RFC8017, pg. 64, for SHA-1, and the SHA-2 family, the algorithm parameter has to be NULL and both explicit NULL parameter and implicit NULL parameter (ie, absent NULL parameter) are considered to be legal and equivalent. However, this implementation does not accept a valid PKCS input with implicit NULL parameter.
Reference notation and concrete values
N
: public modulus|N|
: length of public modulusd
: private exponente
: public exponentH
: hash functionm
: messageI
: to-be-singed RSA PKCS#1 v1.5 signature scheme input structureS
: signature value obtained by I^d mod N
N = 0xE932AC92252F585B3A80A4DD76A897C8B7652952FE788F6EC8DD640587A1EE5647670A8AD4C2BE0F9FA6E49C605ADF77B5174230AF7BD50E5D6D6D6D28CCF0A886A514CC72E51D209CC772A52EF419F6A953F3135929588EBE9B351FCA61CED78F346FE00DBB6306E5C2A4C6DFC3779AF85AB417371CF34D8387B9B30AE46D7A5FF5A655B8D8455F1B94AE736989D60A6F2FD5CADBFFBD504C5A756A2E6BB5CECC13BCA7503F6DF8B52ACE5C410997E98809DB4DC30D943DE4E812A47553DCE54844A78E36401D13F77DC650619FED88D8B3926E3D8E319C80C744779AC5D6ABE252896950917476ECE5E8FC27D5F053D6018D91B502C4787558A002B9283DA7
|N| = 256 bytes
d = 0x009b771db6c374e59227006de8f9c5ba85cf98c63754505f9f30939803afc1498eda44b1b1e32c7eb51519edbd9591ea4fce0f8175ca528e09939e48f37088a07059c36332f74368c06884f718c9f8114f1b8d4cb790c63b09d46778bfdc41348fb4cd9feab3d24204992c6dd9ea824fbca591cd64cf68a233ad0526775c9848fafa31528177e1f8df9181a8b945081106fd58bd3d73799b229575c4f3b29101a03ee1f05472b3615784d9244ce0ed639c77e8e212ab52abddf4a928224b6b6f74b7114786dd6071bd9113d7870c6b52c0bc8b9c102cfe321dac357e030ed6c580040ca41c13d6b4967811807ef2a225983ea9f88d67faa42620f42a4f5bdbe03b
e = 3
H = SHA-256 (OID = 0x608648016503040201)
m = "hello world!"
I = 0x0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00302f300b060960864801650304020104207509e5bda0c762d2bac7f90d758b5b2263fa01ccbc542ab5e3df163be08e6ca9
S = 0xa0073057133ff3758e7e111b4d7441f1d8cbe4b2dd5ee4316a14264290dee5ed7f175716639bd9bb43a14e4f9fcb9e84dedd35e2205caac04828b2c053f68176d971ea88534dd2eeec903043c3469fc69c206b2a8694fd262488441ed8852280c3d4994e9d42bd1d575c7024095f1a20665925c2175e089c0d731471f6cc145404edf5559fd2276e45e448086f71c78d0cc6628fad394a34e51e8c10bc39bfe09ed2f5f742cc68bee899d0a41e4c75b7b80afd1c321d89ccd9fe8197c44624d91cc935dfa48de3c201099b5b417be748aef29248527e8bbb173cab76b48478d4177b338fe1f1244e64d7d23f07add560d5ad50b68d6649a49d7bc3db686daaa7
I am trying to use encryptPKCS and it is returning me a lazy bytestring that hangs when I convert it to a strict one. Seems to be some kind of loop going on.
I'm using RSA-2.1.0.1 from cabal.
The following test case will reproduce this issue:
import Codec.Crypto.RSA
import Crypto.Random
import Crypto.Random.DRBG
import qualified Data.ByteString.Char8 as S
import qualified Data.ByteString.Lazy as L
pub = PublicKey 256 29060443439214279856616714317441381282994349643640084870421944724225051983847478784673076656611842327286248615724611803087461618516721788708203033006691375762945643318357727014263595982166729996386221650476766003639153689499857611134510522816302362939416771427488386015646066278147887150432188755545432365505792541160505770508361650791802130319371355483088627276339169052633563469569700890323453456895458435615439774655448017285792552006383801267107827169345054450617812278338175996674268312779619076725131801425088592558384516012482302720815493207137857605058069804785841016421433023935564657365714364549037012710517 65537
main = do
g <- newGenIO :: IO (GenAutoReseed HashDRBG HashDRBG)
let v = S.pack "testing 1 2 3"
let (v, g') = encryptPKCS g pub v
-- putStrLn $ "lazy: " ++ show v -- <<loop>> !
putStrLn $ "strict: " ++ show (L.toStrict v) -- <<loop>> !
Test.hs:99:8: error:
• No instance for (Control.Monad.Fail.MonadFail Gen)
arising from a do statement
with the failable pattern ‘Right (g :: HashDRBG)’
• In a stmt of a 'do' block:
Right (g :: HashDRBG) <- (newGen . BSS.pack)
`fmap` replicateM 4096 arbitrary
In the expression:
do Right (g :: HashDRBG) <- (newGen . BSS.pack)
`fmap` replicateM 4096 arbitrary
case largeRandomPrime g 64 of
Left _ -> fail "Large prime generation failure."
Right (i, _) -> return (LP i)
In an equation for ‘arbitrary’:
arbitrary
= do Right (g :: HashDRBG) <- (newGen . BSS.pack)
`fmap` replicateM 4096 arbitrary
case largeRandomPrime g 64 of
Left _ -> fail "Large prime generation failure."
Right (i, _) -> return (LP i)
|
99 | do Right (g :: HashDRBG) <- (newGen . BSS.pack) `fmap` replicateM 4096 arbitrary
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This is due to the use of MultiWayIf
which is only available starting with GHC 7.6:
Configuring RSA-2.1.0...
cabal: The package RSA-2.1.0 requires the following language extensions which
are not supported by ghc-7.4.2: MultiWayIf
Failed to install RSA-2.1.0
cabal: Error: some packages failed to install:
RSA-2.1.0 failed during the configure step. The exception was:
ExitFailure 1
Please add a base >= 4.6
constraint to future releases (or make RSA compatible with GHC < 7.6 again)
The RSA test suite runs for over an hour on fairly modern hardware. This feels a little excessive. Is there a way to build the test suite so that it performs testing that's a little less thorough but completes in, say a minute or so?
The docs claim that encrypt
can handle messages of arbitrary size, splitting them as appropriate to fit them into RSA. In the current implementation however, long messages error
.
import Crypto.Random
import Codec.Crypto.RSA
import Data.Binary
main = do
g <- newGenIO :: IO SystemRandom
let msg = "Hello, World!"
putStr "1024 bit key pair: "
g' <- cryptoTest g msg 1024
putStr "128 bit key pair: "
_g'' <- cryptoTest g' msg 128
return ()
-- | Generate a RSA key pair of a given length, and
-- encrypt/decrypt a provided message with it.
-- Prints the decrypted message.
cryptoTest :: CryptoRandomGen gen
=> gen -- ^ RNG
-> String -- ^ Message
-> Int -- ^ RSA modulus length
-> IO gen -- ^ Modified generator
cryptoTest g msg n =
let (public, private, g') = generateKeyPair g n
(encrypted, g'') = encrypt g' public (encode msg)
decrypted = decode (decrypt private encrypted) :: String
in putStrLn decrypted >> return g''
Output:
> runhaskell test.hs
1024 bit key pair: Hello, World!
128 bit key pair: test.hs: message too long (rsaes_oaep_encrypt)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.