-- | -- Module : Data.Certificate.Key -- License : BSD-style -- Maintainer : Vincent Hanquez -- Stability : experimental -- Portability : unknown -- -- Read/Write Private/Public RSA Key -- module Data.Certificate.KeyRSA ( decodePublic , decodePrivate , encodePublic , encodePrivate , parse_RSA ) where import Data.ASN1.Stream import Data.ASN1.Encoding import Data.ASN1.BinaryEncoding import Data.ASN1.BitArray import qualified Data.ByteString.Lazy as L import qualified Crypto.Types.PubKey.RSA as RSA parsePublic :: [ASN1] -> Either String RSA.PublicKey parsePublic [ Start Sequence , Start Sequence , OID [1,2,840,113549,1,1,1] -- PubKeyALG_RSA , Null , End Sequence , BitString (BitArray _ as1n) , End Sequence ] = parse_RSA as1n parsePublic _ = Left "unexpected format" decodePublic :: L.ByteString -> Either String RSA.PublicKey decodePublic dat = either (Left . show) parsePublic $ decodeASN1 BER dat encodePublic :: RSA.PublicKey -> L.ByteString encodePublic p = encodeASN1 DER [ Start Sequence , Start Sequence , OID [1,2,840,113549,1,1,1] -- PubKeyALG_RSA , Null , End Sequence , BitString $ toBitArray innerSeq 0 , End Sequence ] where innerSeq = encodeASN1 DER [ Start Sequence , IntVal $ RSA.public_n p , IntVal $ RSA.public_e p , End Sequence ] parsePrivate :: [ASN1] -> Either String (RSA.PublicKey, RSA.PrivateKey) parsePrivate [ Start Sequence , IntVal 0, IntVal p_modulus, IntVal pub_exp , IntVal priv_exp, IntVal p_p1, IntVal p_p2 , IntVal p_exp1, IntVal p_exp2, IntVal p_coef , End Sequence ] = Right (pubkey, privkey) where privkey = RSA.PrivateKey { RSA.private_size = calculate_modulus p_modulus 1 , RSA.private_n = p_modulus , RSA.private_d = priv_exp , RSA.private_p = p_p1 , RSA.private_q = p_p2 , RSA.private_dP = p_exp1 , RSA.private_dQ = p_exp2 , RSA.private_qinv = p_coef } pubkey = RSA.PublicKey { RSA.public_size = calculate_modulus p_modulus 1 , RSA.public_n = p_modulus , RSA.public_e = pub_exp } calculate_modulus n i = if (2 ^ (i * 8)) > n then i else calculate_modulus n (i+1) parsePrivate (Start Sequence : IntVal n : _) | n == 0 = Left "RSA key format: not recognized" | otherwise = Left ("RSA key format: unknown version " ++ show n) parsePrivate _ = Left "unexpected format" decodePrivate :: L.ByteString -> Either String (RSA.PublicKey, RSA.PrivateKey) decodePrivate dat = either (Left . show) parsePrivate $ decodeASN1 BER dat encodePrivate :: (RSA.PublicKey, RSA.PrivateKey) -> L.ByteString encodePrivate (pubkey, privkey) = encodeASN1 DER pkseq where pkseq = [ Start Sequence , IntVal 0 , IntVal $ RSA.private_n privkey , IntVal $ RSA.public_e pubkey , IntVal $ RSA.private_d privkey , IntVal $ RSA.private_p privkey , IntVal $ RSA.private_q privkey , IntVal $ RSA.private_dP privkey , IntVal $ RSA.private_dQ privkey , IntVal $ fromIntegral $ RSA.private_qinv privkey , End Sequence ] {- | parse a RSA pubkeys from ASN1 encoded bits. - return RSA.PublicKey (len-modulus, modulus, e) if successful -} parse_RSA :: L.ByteString -> Either String RSA.PublicKey parse_RSA bits = case decodeASN1 BER bits of Right [Start Sequence, IntVal modulus, IntVal pubexp, End Sequence] -> Right $ RSA.PublicKey { RSA.public_size = calculate_modulus modulus 1 , RSA.public_n = modulus , RSA.public_e = pubexp } _ -> Left "bad RSA format" where calculate_modulus n i = if (2 ^ (i * 8)) > n then i else calculate_modulus n (i+1)