Skip to content
This repository has been archived by the owner on Sep 20, 2023. It is now read-only.

Reading/writing RSA keys from files #69

Open
timbod7 opened this issue Feb 25, 2016 · 20 comments
Open

Reading/writing RSA keys from files #69

timbod7 opened this issue Feb 25, 2016 · 20 comments

Comments

@timbod7
Copy link

timbod7 commented Feb 25, 2016

I'm using some of the functions in Crypto.PubKey.RSA, and wish to read and write PEM files compatible with openssl. I need functionality equivalent to these functions from OpenSSL.PEM:

  • writePKCS8PrivateKey
  • readPrivateKey
  • writePublicKey
  • readPublicKey

Are there functions in some library compatible with Crypto.PubKey.RSA to do this?

@vincenthz
Copy link
Member

vincenthz commented Apr 19, 2016

There's some functions that do that in the certificate packages (x509,..) and tls, but it's lacking a canonical place to put this.

Edit: I'm thinking a new cryptonite-storage package to collect all the necessary stuff related to storing cryptographic stuff would be nice. opinions ?

@Xandaros
Copy link

Thanks for the hint with x509. I was looking to decode a public key I had as a ByteString.
It would be really nice to have a way to decode public keys without depending on three entirely different libraries.

Right now, I need to use asn1-encoding and asn1-types (I count those as one library) to decode the ByteString and get a [ASN1].
I then need to use x509 to turn the [ASN1] into a PublicKey, which is from the cryptonite package... which is what I intended to use in the first place.

I really think there should be a way to convert from the more common encodings (straight ASN1, PEM, etc.) directly to a PublicKey without going library-hopping.

@ghost
Copy link

ghost commented Aug 18, 2017

@vincenthz Along with this, is it possible to add instances of ASN1Object for RSA private keys to support serialization/deserialization?

@chris-martin
Copy link
Contributor

Related issue in hs-certificate for RSA private keys: haskell-tls/hs-certificate#55

@ecthiender
Copy link

ecthiender commented Apr 18, 2018

So I have read through the comments but I still don't understand which package to use to convert the PrivateKey type into a PEM format. I'm generating a key pair using the generate function from Crypto.PubKey.RSA module. I have looked into packages x509 and tls, and I don't understand which function can I use to go from type PrivateKey of cryptonite to PEM format.

@Xandaros's method doesn't work for me. They wanted ByteString -> PublicKey, I want PrivateKey -> <PEM>.

Excuse my ignorance, I'm not familiar with crypto etc. My use-case is, I want to generate public, private key pair for SSH. Any nudge in the right direction would be appreciated.

@ProofOfKeags
Copy link

Is there a solution for ECDSA for this?

@ProofOfKeags
Copy link

@vincenthz I'd be willing to take on some of the work to do a cryptonite-storage library. Unless it's already started. to your knowledge is this already started or should I start a new project for it?

@ocheron
Copy link
Contributor

ocheron commented Jul 29, 2018

FYI I have a package in progress for this, already able to parse (un)encrypted private keys.
PKCS #12 should come very soon.

@asheshambasta
Copy link

Has anyone had any success in writing a PrivateKey to a PEM string? If so, I'll appreciate any help.

@asheshambasta
Copy link

In case this may help anyone, here's my quick and (very) dirty solution for writing a PrivateKey as to PEM: https://gist.github.com/asheshambasta/001986992ad41ee82e4b042054df4efb

@ProofOfKeags
Copy link

ProofOfKeags commented Aug 14, 2018 via email

@sigrlami
Copy link

sigrlami commented Oct 8, 2018

@asheshambasta do you have solution for reading?

@asheshambasta
Copy link

asheshambasta commented Oct 10, 2018

@sigrlami If you're referring to reading RSA keys from PEM, I believe something like this achieves that:

import qualified Data.ByteString as B 
import qualified Crypto.PubKey.OpenSsh.Decode as D
import qualified Crypto.PubKey.OpenSsh.Types as T
import qualified Crypto.Types.PubKey.RSA as CRSA

-- | Read private RSA Key in PEM format
readPemRsaKey' :: MonadIO m
               => FilePath -- ^ file path to read key from; must be PEM
               -> m (Either PrivateKeyError CRSA.PrivateKey)
readPemRsaKey' path = do
  exists <- liftIO $ doesFileExist path
  if exists then do
    eKey <- liftIO $ D.decodePrivate <$> B.readFile path
    return $ case eKey of
      Right (T.OpenSshPrivateKeyRsa k) -> Right k
      Right other                    -> Left NotRSA
      Left err                       -> Left . ParseErr $ err
  else return . Left . NoKey $ path

edit: cleaned up the snippet.

@crockeea
Copy link

crockeea commented Feb 6, 2019

@ocheron

FYI I have a package in progress for this, already able to parse (un)encrypted private keys.
PKCS #12 should come very soon.
What's the status on this?

@crockeea
Copy link

crockeea commented Feb 6, 2019

@vincenthz What's the status of cryptonite-storage? I was thinking of creating something similar.

@ocheron
Copy link
Contributor

ocheron commented Feb 10, 2019

@ocheron [...] What's the status on this?

It's there: https://github.com/ocheron/cryptostore.
Mostly a learning project for me but I released a version on hackage if useful to others.

@mDantas
Copy link

mDantas commented Apr 16, 2019

@asheshambasta thanks for your snippet. Using it, I was able to successfully parse a PrivateKey from a .pem file. I'm now having trouble because it looks like I actually need a PrivateKey type as defined in the cryptonite library and not as defined in crypto-pubkey-types. Specifically, I'm trying to create a JWT from an RSA private key (see fromRSA here).

I don't see any way to convert between the two libraries' PrivateKey types.

I feel like I'm doing something silly wrt dependency management. For what it's worth, I'm using stack with the lts-12.26 snapshot.

Here is my type-error.

    • Couldn't match expected type ‘Crypto.PubKey.RSA.Types.PrivateKey’
                  with actual type ‘PrivateKey’
      NB: ‘PrivateKey’
            is defined in ‘Crypto.Types.PubKey.RSA’
                in package ‘crypto-pubkey-types-0.4.3’
          ‘Crypto.PubKey.RSA.Types.PrivateKey’
            is defined in ‘Crypto.PubKey.RSA.Types’
                in package ‘cryptonite-0.25’
    • In the first argument of ‘fromRSA’, namely ‘pk’
      In the expression: fromRSA pk
      In an equation for ‘jwk’: jwk = fromRSA pk
    |
114 |   let jwk = fromRSA pk

Any ideas?

@Xandaros I read through your comment and suspect I could do something similar to library-hop my way from a ByteString to a cryptonite PrivateKey, but I'm getting lost on the specifics in using x509 to go from [ASN1] to PrivateKey. Thoughts there?

@asheshambasta
Copy link

@mDantas I've encountered this before. The problem is what you've correctly identified: the PrivateKey type comes from 2 packages. If I remember correctly; the only way for me to solve this was to have to manually copy the fields into the data constructors. However, my memory is blurry about this and I can look it up in my old project if you need.

@Xandaros
Copy link

Xandaros commented Apr 18, 2019

@mDantas The x509 package defines a PrivKey type, which implements ASN1Object. asn1-types defines a Data.ASN1.Types.fromASN1 :: (ASN1Object a) => [ASN1] -> Either String (a, [ASN1]) . Use that to get the PrivKey, which in turn contains the cryptonite PrivateKey

@freckletonj
Copy link

This just drove me crazy. So ssh-keygen and openssl make subtly different keys, and ssh-keygens are not understood as PEM keys. Use something like openssl genrsa -out privateKey.pem 4096.

Then @CaptJakk 's recommendation works great: ProofOfKeags/wai-jwt-auth-middleware#1

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests