RSA Sign using a PrivateKey from a file
encryption, haskell, rsa
Solution
I needed something similar, so I added a bit of serialization/deserialization to the package `crypto-pubkey-openssh` a while back. It doesn't handle encrypted or ECC keys, but suffices for most needs.
As my comment said, you want something like:
import Codec.Crypto.RSA (sign)
import Crypto.PubKey.OpenSsh (decodePrivate, OpenSshPrivateKey)
import Crypto.Types.PubKey.RSA (PrivateKey)
import Data.ByteString (ByteString)
throwLeft :: Either String OpenSshPrivateKey -> PrivateKey
throwLeft (Right (OpenSshPrivateKeyRsa k)) = k
throwLeft (Right _) = error "Wrong key type"
throwLeft (Left s) = error $ "Error reading keys: " ++ s
readAndSign :: FilePath -> ByteString -> IO ByteString
readAndSign file msg = (flip sign msg . throwLeft . decodePrivate) `fmap` readFile file
Notice this code is untested, but the building blocks should be correct. You want to read in a private key (`readFile`, `decodePrivate`). Perform some error checking (`throwLeft`) and sign the message (`sign`).
EDIT: I felt it was productive to identify in what way this is longer than the Python example in the question. It appears as though the building blocks are the same but the level of abstraction exposed by the library is very different along with the error handling (explicit vs exceptions). If we assume the library authors did a little more work by re-exporting everything from one module and defined a helper:
loadKey :: FilePath -> IO PrivateKey
loadKey p = (throwLeft . decodePrivate) `fmap` readFile p
Then the code is nearly identical:
k <-loadKey keyFile
let result = sign k msg
Problem
Using Haskell, how can you sign using an existing private key from a file? In Python, it is as simple as - ``` import M2Crypto rsa = M2Crypto.RSA.load_key("path/to/key") result = rsa.sign("foo") ``` It seems you can sign using the `Codec.Crypto.RSA` module - http://hackage.haskell.org/package/RSA-1.0.6.2/docs/Codec-Crypto-RSA.html#g:2 But I only see how to generate new private keys from that module, not use an existing one. It seems that the `Network.TLS.Extra` module provides reading a private key from a file - http://hackage.haskell.org/package/tls-extra-0.6.1/docs/Network-TLS-Extra.html#g:6 Unfortunately, the PrivateKey type exported from each of the modules are not compatible with each other - ``` Couldn't match expected type `crypto-pubkey-types-0.4.0:Crypto.Types.PubKey.RSA.PrivateKey' with actual type `tls-1.1.5:Network.TLS.Crypto.PrivateKey' ```