-- KeyInfo.hs: OpenPGP (RFC4880) fingerprinting methods
-- Copyright © 2012-2018  Clint Adams
-- This software is released under the terms of the Expat license.
-- (See the LICENSE file).
module Codec.Encryption.OpenPGP.KeyInfo
  ( pubkeySize
  , pkalgoAbbrev
  ) where

import qualified Crypto.PubKey.DSA as DSA
import qualified Crypto.PubKey.ECC.ECDSA as ECDSA
import qualified Crypto.PubKey.ECC.Types as ECCT
import qualified Crypto.PubKey.RSA as RSA
import Data.Bits (shiftR)
import Data.List (unfoldr)

import Codec.Encryption.OpenPGP.Types

pubkeySize :: PKey -> Either String Int
pubkeySize :: PKey -> Either String Int
pubkeySize (RSAPubKey (RSA_PublicKey x :: PublicKey
x)) = Int -> Either String Int
forall a b. b -> Either a b
Right (PublicKey -> Int
RSA.public_size PublicKey
x Int -> Int -> Int
forall a. Num a => a -> a -> a
* 8)
pubkeySize (DSAPubKey (DSA_PublicKey x :: PublicKey
x)) =
  Int -> Either String Int
forall a b. b -> Either a b
Right (Integer -> Int
bitcount (Integer -> Int) -> (PublicKey -> Integer) -> PublicKey -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Params -> Integer
DSA.params_p (Params -> Integer)
-> (PublicKey -> Params) -> PublicKey -> Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PublicKey -> Params
DSA.public_params (PublicKey -> Int) -> PublicKey -> Int
forall a b. (a -> b) -> a -> b
$ PublicKey
x)
pubkeySize (ElGamalPubKey p :: Integer
p _ _) = Int -> Either String Int
forall a b. b -> Either a b
Right (Integer -> Int
bitcount Integer
p)
pubkeySize (ECDSAPubKey (ECDSA_PublicKey (ECDSA.PublicKey curve :: Curve
curve _))) =
  Int -> Either String Int
forall a b. b -> Either a b
Right (Int -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Curve -> Int
ECCT.curveSizeBits Curve
curve))
pubkeySize (ECDHPubKey (ECDSAPubKey (ECDSA_PublicKey (ECDSA.PublicKey curve :: Curve
curve _))) _ _) =
  Int -> Either String Int
forall a b. b -> Either a b
Right (Int -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Curve -> Int
ECCT.curveSizeBits Curve
curve))
pubkeySize (ECDHPubKey (EdDSAPubKey Ed25519 _) _ _) = Int -> Either String Int
forall a b. b -> Either a b
Right 256
pubkeySize (EdDSAPubKey Ed25519 _) = Int -> Either String Int
forall a b. b -> Either a b
Right 256
pubkeySize x :: PKey
x = String -> Either String Int
forall a b. a -> Either a b
Left (String -> Either String Int) -> String -> Either String Int
forall a b. (a -> b) -> a -> b
$ "Unable to calculate size of " String -> String -> String
forall a. [a] -> [a] -> [a]
++ PKey -> String
forall a. Show a => a -> String
show PKey
x

bitcount :: Integer -> Int
bitcount :: Integer -> Int
bitcount =
  (Int -> Int -> Int
forall a. Num a => a -> a -> a
* 8) (Int -> Int) -> (Integer -> Int) -> Integer -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
  [Bool] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([Bool] -> Int) -> (Integer -> [Bool]) -> Integer -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
  (Integer -> Maybe (Bool, Integer)) -> Integer -> [Bool]
forall b a. (b -> Maybe (a, b)) -> b -> [a]
unfoldr
    (\x :: Integer
x ->
       if Integer
x Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== 0
         then Maybe (Bool, Integer)
forall a. Maybe a
Nothing
         else (Bool, Integer) -> Maybe (Bool, Integer)
forall a. a -> Maybe a
Just (Bool
True, Integer
x Integer -> Int -> Integer
forall a. Bits a => a -> Int -> a
`shiftR` 8))

-- FIXME: redo these for hOpenPGP 3
pkalgoAbbrev :: PubKeyAlgorithm -> String
pkalgoAbbrev :: PubKeyAlgorithm -> String
pkalgoAbbrev RSA = "R"
pkalgoAbbrev DSA = "D"
pkalgoAbbrev ElgamalEncryptOnly = "g"
pkalgoAbbrev DeprecatedRSAEncryptOnly = "-"
pkalgoAbbrev DeprecatedRSASignOnly = "_"
pkalgoAbbrev ECDH = "e"
pkalgoAbbrev ECDSA = "E"
pkalgoAbbrev ForbiddenElgamal = "f"
pkalgoAbbrev DH = "d"
pkalgoAbbrev EdDSA = "w"
pkalgoAbbrev (OtherPKA _) = "."