#! /usr/bin/perl
use warnings;
use Math::BigInt lib => 'GMP';
use Digest::SHA qw(sha256_hex);

my $filename = shift;

open FH,"< $filename" or die "Can't open file $filename: $!";
my $firmware;
read(FH,$firmware,-s $filename);

open FH,"< $filename.sig" or die "Can't open file $filename.sig: $!";
my $signature;
read(FH,$signature,-s "$filename.sig");

if(verifySignature($firmware,$signature)){
    print "Signature verification ok\n";
} else{
    print "Signature verification failed!\n";
}

sub verifySignature{
    my($firmware,$firmwareSignature) = @_;
    my $shaRealValue = sha256_hex($firmware);
    # 8192 bit RSA should be enough (unless those damn hackers have brought a quantum computer with them).
    my $n = new Math::BigInt("0xda78cdbdee8067fb21d3479a49f227ab8b8ecc5f00cdb45fe4a6419bf1e9b9c01f7430937742113cc3f1aadb03dd5df8cb3e46e44eecdbb74cb0e83cad66a4d62b06a31464b4f1cee04bc096b3ea080c00bd8988e2dcc6289021fbe2ca32311baabba83ee7b453395376867ee736d22b4ccb0c3c95d50794ca83e6b2d9a5fdc46d593e6eea75d25ac616adb146e0f6550fa59fc57681230177232ce2eb4389997949f8160410ec583bee73c5abdd13e4a227b756fd430e0d7c7c9ff5d729e525723765c49fef5677f14424c28ce7252351210f365d1a4553be66ae8aab11ccd80a32baa9968fcf02a4bb79c31d6e2d5d74d27279ecb93faca96f9c424bdea4aca9cf318e4707869d26c9bc576d19ed047e66d26e9fd1fca4aaaf8ad097ba3cc90080a234c435fad84c0c9731b889c40455a7a4c4c6784cb90de7b5f9237439b6cfbe3aaf805faeca5edb37ae8004c025a6fa45bc0f8470981bb809e92b13d32b65449eb6354be1c48cb600d1a5cbdbefb74ee2bd8f75b374630b214e63cb7968421a7d5a4fc63095656be41cd52d7ed01761a21b502144e84df226d9adc1961568783890735fee905267820664c16157566b0b6bb387edd9bea8c3b4bcbbc0be23703f3aefae3400deefc3a9c3774d4322df0b4a6703d0c064af0068f49fac21a285bd6bec17de379acd7e4fec586cb028ad9a37fa16b8dea0b9ef2a68e1d7c91f671d37f0c36715d13889f91147cff8e1bd6a10bdd385706666b4f17daf6e709feb9fd235784512591ff1501740ee11a76e4dd823cf8fb8d0187f853fcaa6b7de33e8b3fdba4d5e53b6c7d7187d087a56548e47e01bc48e10c0a2fda1e8cc37ff3e17c77f89e576aef53cb42c1b0a2a225461e4d292b3948b153b677bba320f7f1ab7d024b2f43ec1bb2a1f9271e3b47e5a25655a84066770450cf3dc0df4319b292b9ec92e25030dc3aee2271297988380c9369bf81f1b92fabc6b1bb41af396c73220d449053ff9a1afa3fbfd0d7a724165e528ffa5e251555bec71b846ff29ec1fdc64455a5f87ea818a062295b3493190fb91fb8bda2b3c476cfda87d2c5addd9a33c3c57700d040112631cfac1badefb4de631aac51b08b93c7a27ff5034fb05260a79718ff53694973fa6b83b696ae3941ad11a6fcb011c63b167fa4e502b4e4c979283d401af1904ac9aede7c32c7d0b8d7164e207ac4ef407f95c8a5e89e56a8cc43344699400544607b67136a263ae7414c65641ca94fb5952ee1f256a8a57fdd3cad4be711b20d129fc4d345475dda5feddb693ced9d91fda7f8a2ef0e6f7ccedaa147117f3ac89e56fc2a01e540f890ada32d0d13fa371e1ba878947494f5d60df5d692d709bcb578a703cb5bd3e0f0105fc526a164935bc63200e65139b27b30f0a67aa00fb3fa93adb738b252e8013b5c2e499e69a16ca8697");
    my $e = new Math::BigInt("0x11");
    # Validate that the signature isn't too long and contains only valid characters
    if(length($firmwareSignature) > 5000 or $firmwareSignature !~ /^0x[0-9a-f]+$/){
	return 0;
    }
    # Convert the hexadecimal signature to a Math::BigInt number
    my $signature = new Math::BigInt($firmwareSignature);
    # Do the RSA Operation: $signature = ( $signature ** $e ) % $n
    $signature->bmodpow($e,$n);
    # The lower 256 bits (64 hex digits) should be equal to the sha256 value of the firmware.
    my $shaExpectedValue = substr($signature->as_hex(),-64);
    if($shaExpectedValue eq $shaRealValue){
	return 1;
    } else{
	return 0;
    }
}

