packages feed

Crypto-3.0.3: RSAVerifyExample.hs

module Main(main) where

import System.IO
import Data.Char
import Data.List
import System.Environment
import System.Console.GetOpt
import Data.Maybe
import Codec.ASN1
import Codec.Utils
import Data.Digest.SHA1
import Codec.Encryption.RSA
import Codec.ASN1.TLV
import Codec.ASN1.X509
import Codec.ASN1.BER
import NewBinary.Binary
import qualified Codec.ASN1.PKCS1v15 as V15

verifyWith certFile plainTextFile signedFile = 
{-
certFile should contain an X.509 certificate.
-}
   do hcert   <- openFile certFile ReadMode
      hplain  <- openFile plainTextFile ReadMode
      hsign   <- openFile signedFile ReadMode
      ptext   <- hGetContents hplain
      psign   <- hGetContents hsign
      bin     <- openBinIO_ hcert
      (_,x)   <- tlvIO bin
{-
Typecheck this is really a signed certificate.
-}
      (w,sc) <- typeCheck signedCertificate x
{-
If it is then decode it and extract the bitstring containing the RSA
public key.
-}
      let (_ ::= c) = w
          d  = decode c (Just sc)
          d1 = certificate1 (fromJust d)
          d2 = subjectPublicKeyInfo2 d1
          d3 = subjectPublicKeyInfo1 d2
          (BitString e) = d3
          (_,x') = tlv e
{-
Typecheck this really is an RSA public key.
-}
      (w',rpk) <- typeCheck rsaPublicKey x'
{-
If it is then decode it and extract the modulus and the public
exponent.
-}
      let (_ ::= r) = w'
          s  = (decode r (Just rpk))
          n  = toOctets 256 $ modulus1 $ fromJust s 
          d  = toOctets 256 $ publicExponent1 $ fromJust s
{-
Decrypt the signature.
-}
          sd = decrypt (n,d) (map (fromIntegral . ord) psign)
          md = V15.decode sd
          di = fromJust md
          (l,v) = tlv $ di
      if md == Nothing 
         then error "Decryption error"
         else do (w'',w) <- typeCheck V15.digestInfo v
                 let (_ ::= d) = w''
                     e = decode d (Just w)
                 putStrLn (show (V15.digestAlgorithm1 (fromJust e)))
                 putStrLn ("Given digest:      " ++ (show (V15.digest (fromJust e))))
{-
Compute the hash of the plaintext file which the signature is
purported to have signed.
-}
                 let h  = hash $ map (fromIntegral . ord) ptext
                     g = OctetString h
                 putStrLn ("Calculated digest: " ++ (show g))
                 if (V15.digest (fromJust e) == g)
                    then putStrLn "Verified"
                    else putStrLn "Unable to verify"

main = do pn <- getProgName
          args <- getArgs
          (fs,ss) <- opts pn args
          let sfs        = sort fs
              (Cert e)   = sfs!!0
              (Input i)  = sfs!!1
              (Sig s)    = sfs!!2
          verifyWith e i s

data Flag = Cert String | Input String | Sig String 
   deriving (Show,Eq,Ord)

options = [
   Option ['e'] ["cert","certificate"]  (ReqArg Cert "CERT")
          "Certificate File",
   Option ['p'] ["plain","plaintext"]   (ReqArg Input "INPUT")
          "Plaintext File",
   Option ['s'] ["sig","signature"]     (ReqArg Sig "SIGNATURE")
          "Signature File"
   ]
    
opts :: String -> [String] -> IO ([Flag], [String])
opts progName argv = 
   case getOpt Permute options argv of
      (o,n,[]  ) -> 
         if length o == 3
            then return (o,n)
            else ioError (userError (usageInfo header options))
      (_,_,errs) -> 
         ioError (userError (concat errs ++ usageInfo header options))
      where header = "Usage: " ++ progName ++ " [OPTION...] files..."