Search code examples
crystal-lang

How can I verify a pem_cert and signiture (RSA-SHA1)?


I'm trying to check if a signature is valid, in Node.js I would use

https://nodejs.org/api/crypto.html#crypto_verify_verify_object_signature_signatureencoding

I can't seem to find anything for crystal that provides this functionality?


Solution

  • This is currently not implemented in the standard library, but we can find a shard that does it: openssl_ext. This shards closely resembles the Ruby API, so let's get going!

    First we need a key:

    $ openssl genpkey -algorithm rsa -out key.pem
    $ openssl rsa -in key.pem -pubout -out pub.pem
    

    Then we need to create a shard and add the dependency:

    $ shards init
    $ $EDITOR shards.yml
    
    dependencies:
       openssl_ext:
          github: randomstate/openssl_ext
    
    $ shards
    

    A small program to sign something:

    $ $EDITOR sign.cr
    
    require "openssl_ext"
    require "base64"
    
    private_key = OpenSSL::RSA.new File.read(ARGV[0])
    digest = OpenSSL::Digest.new("SHA1")
    
    data = ARGV[1]
    signature = private_key.sign digest, data
    
    puts Base64.encode signature
    
    $ crystal build sign.cr
    

    And a small program to verify a signature:

    $ $EDITOR verify.cr
    
    require "openssl_ext"
    require "base64"
    
    public_key = OpenSSL::RSA.new File.read(ARGV[0]), is_private: false
    digest = OpenSSL::Digest.new("SHA1")
    
    data = ARGV[1]
    signature = Base64.decode STDIN.gets_to_end
    
    puts public_key.verify(digest, signature, data) ? "Valid" : "Invalid"
    
    $ crystal build verify.cr
    

    Let's test our work:

    $ ./sign key.pem Hello | ./verify pub.pem Hello
    Valid
    $ ./sign key.pem Hello | ./verify pub.pem Bye
    Invalid