How can this openSSL command be emulated with phpseclib: RSA
openssl pkeyutl -verify -in gfeHmac.bin -sigfile privkey2_140225_gfesig.bin -pubin -inkey pubkey2_140225.pem -pkeyopt digest:sha256 -pkeyopt rsa_padding_mode:pss -pkeyopt rsa_pss_saltlen:-1
Here is the basic php stub that fails to verify:
include('phpseclib0.3.6/Math/BigInteger.php');
include('phpseclib0.3.6/Crypt/Hash.php');
include('phpseclib0.3.6/Crypt/TripleDES.php');
include('phpseclib0.3.6/Crypt/RSA.php');
echo "<hr>Using: phpseclib0.3.6/Crypt/RSA.php<br>";
function getCrntRsaPbKey()
{
return "-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDmA6xcIcBo0UiVxzduHFjks511
R5Y+gsvn6rVyjIWSQZt0h8N8vJPreDCDcOybToFmJMnz8R8aohC6ipJ0nIaI644+
oXVQkKGEjaAFKn+L6AEUQSZKkkbmEjBqDSriq91q8U78Ky6xT5a5JpuHz+QEgGi2
SXf1t3EBec1vjgMycQIDAQAB
-----END PUBLIC KEY-----";
} // private function getCrntRsaPbKey($incoming)
$origData = "4hZpNOnmgAlqkCCLMJ8MKv1pC73aTReA7Pht4hnc4Os=";
echo "<hr>original base64 hash payLoad:";
var_dump ( $origData );
$signedUsePrv = "Rzwo6eiCDf/w7f69JcKuq7a0czlAXuLXsgJbat2GRc6Tvv3CH04/ccpOZoV2+NKA5tew1QH3Ic+M
qhYJkRA5l+bK6RIuEuxQ8Eo5qSpxBHmmup41INTiR4xRB2KSp+uNgj2Nw2+GAmfpK+nx53sXcxkD
ZnB+njlJTkuhx4iKmM8=";
echo "<hr>original signed digest base64 payLoad:";
var_dump ( $signedUsePrv );
$rsa = new Crypt_RSA();
//$rsa->setMGFHash('sha256');
$rsa->setHash('sha256');
//echo "<hr>\$rsa->setHash('sha256')";var_dump($tst);
//$rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
//$rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS1);
//$rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PSS);
//$rsa->setSaltLength(-1);
echo "<hr>\$rsa:";var_dump ( $rsa );
$pubKey = getCrntRsaPbKey();
echo ("<hr>publickeytest can load<br>" . $pubKey);
$rsaLoadKeyRslt = $rsa->loadKey(($pubKey));
echo "<br>\$rsa->loadKey(\$pubKey):";var_dump ( $rsaLoadKeyRslt );
$rsaVerifyRslt = $rsa->verify ( base64_decode ( $origData ), ( $signedUsePrv ) );
echo "<hr>\$rsa->verify with Eric provided public and signature file:";var_dump ( $rsaVerifyRslt );
if ($rsaVerifyRslt==1)
{
echo "<br>isSigned true , using Remotely Signed signature";
}
phpseclib uses PSS by default for signature verification and uses a salt length of -1 by default as well (well it uses a salt length equal to the hash length which is what the -1 means I think).
The only thing from that that's different than what phpseclib is doing by default is that it's using sha256 whereas phpseclib uses sha1 by default.
Anyway in light of that I think this'll do what you're wanting:
<?php
include('Crypt/RSA.php');
$rsa = new Crypt_RSA();
$rsa->loadKey(file_get_contents('privatekey.txt'));
$rsa->loadKey($rsa->getPublicKey());
$rsa->setHash('sha256');
$rsa->setMGFHash('sha256');
echo $rsa->verify(
file_get_contents('plaintext.txt'),
file_get_contents('signature.txt')
) ? 'verified' : 'unverified';
Related
I have the following code for printing and generating a public and private key:
#include <openssl/err.h>
#include <openssl/ec.h>
#include <openssl/pem.h>
int main()
{
BIO* outbio = NULL;
EC_KEY* myecc = NULL;
EVP_PKEY* pkey = NULL;
outbio = BIO_new_fp(stdout, BIO_NOCLOSE);
myecc = EC_KEY_new_by_curve_name(NID_secp256k1);
EC_KEY_generate_key(myecc);
pkey = EVP_PKEY_new();
EVP_PKEY_assign_EC_KEY(pkey, myecc);
myecc = EVP_PKEY_get1_EC_KEY(pkey);
const EC_GROUP* ecgrp = EC_KEY_get0_group(myecc);
BIO_printf(outbio, "ECC Key size: %d bit\n", EVP_PKEY_bits(pkey));
BIO_printf(outbio, "ECC Key type: %s\n", OBJ_nid2sn(EC_GROUP_get_curve_name(ecgrp)));
PEM_write_bio_PrivateKey(outbio, pkey, NULL, NULL, 0, 0, NULL);
PEM_write_bio_PUBKEY(outbio, pkey);
}
This produces output such as this:
ECC Key size: 256 bit
ECC Key type: secp256k1
-----BEGIN PRIVATE KEY-----
MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQgFAwnckdtDYrNJUbl+sxv
wkUEZCaZTy69C/Mo957vlRihRANCAARgj+NiB2pCJkwb3yPmbD6Rxf/DIgOnbUwr
6sQrmwgq7kBqKVYp7Ar6GdqmnvXB/fSWBWCBzgT6oJO6v5Ixc0T2
-----END PRIVATE KEY-----
-----BEGIN PUBLIC KEY-----
MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEYI/jYgdqQiZMG98j5mw+kcX/wyIDp21M
K+rEK5sIKu5AailWKewK+hnapp71wf30lgVggc4E+qCTur+SMXNE9g==
-----END PUBLIC KEY-----
This looks correct, however if I try to apply these keys to https://8gwifi.org/ecsignverify.jsp the keys do not function properly. If I put the keys in the public/private key input boxes, I get "null EC Private Key is not valid for Signature generation". I do not understand at all what the problem is.
Secondly, I intend to store these keys in some type of string format so that I can load them into memory easily. But how would I go about doing both a signing and verification using these two keys in string format in OpenSSL? I do not understand the ECDSA_sign function parameters nor the ECDSA_verify function parameters.
I am generating ECDSA Prime256 keypair using OpenSSL with C++ and trying to import the hex version of the public key using Java. I pass the byte array I obtain from C++ to the following function in java which expects the byte array to be in an X.509 encoded format.
public static PublicKey getPublicKey(byte[] pk) throws NoSuchAlgorithmException, InvalidKeySpecException {
EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(pk);
KeyFactory kf = KeyFactory.getInstance(Constant.KEY_FACTORY_TYPE);
PublicKey pub = kf.generatePublic(publicKeySpec);
return pub;
}
I create an elliptic curve key pair using the following function which retuns an EC_KEY*
EC_KEY* generate_keypair() {
EC_KEY *eckey = EC_KEY_new();
EC_GROUP *ecgroup = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
EC_KEY_set_group(eckey, ecgroup);
EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE);
int kpGenerationStatus = EC_KEY_generate_key(eckey);
if (kpGenerationStatus) {
return eckey;
}
return nullptr;
}
Given the keypair returned by the function above, I want to export the public key to an ASN1.DER format which can be imported using the java method above.
I convert the public key which is of type EC_POINT* to its hex form using EC_POINT_point2hex() by doing the following:
EC_GROUP *ecgroup = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
EC_KEY *keypair = generate_keypair();
char *result = NULL;
BN_CTX *ctx;
ctx = BN_CTX_new();
const EC_POINT *pub = EC_KEY_get0_public_key(keypair);
result = EC_POINT_point2hex(ecgroup, pub, POINT_CONVERSION_UNCOMPRESSED, ctx);
printf("%s\n", result);
Which return the following:
04F588CD1D7103A993D47E53D58C3F40BE8F570604CF2EA01A7657C1423EB19C51BC379F0BEE1FAA60BB9A07DE73EA9BEF7709C1C6429D4051B44F73A458FFB80D
When I inspect this with the ASN.1 decoder I see a message which says Length over 48 bits not supported at position 1 and trying to import it using the java method I receive an error as follows:
java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException: DerInputStream.getLength(): Should use short form for length
Is there something I am missing while exporting the public key from EC_POINT* to a X.509 Encoded hex string that I can import for validating any signatures?
You are going in the incorrect direction as you want ASN1 base64 value.
EC_POINT_point2hex is converting the internal public key value to hex. It's not in ASN1 format.
You can produce what you want from the command line like so:
Generate EC private key:
openssl ecparam -name prime256v1 -genkey -noout -out key.pem
Extra public key in DER(ASN1) format:
openssl ec -in key.pem -pubout -outform der -out public.cer
Convert to base64
openssl base64 -in .\public.cer
If you take that output and paste it into ASN.1 decoder link it works fine.
Now to turn this into code, you have the EC key generation, but what you want is the steps to:
Generate ASN1 formatted public key
Convert it to base64
To generate the ASN1 formatted public key you want to use the i2d_EC_PUBKEY set of methods and then convert to base64 using BIO_f_base64 filter.
So here is an example problem that when I copy the output to ASN.1 decoder link it works fine.
#include <openssl/bio.h>
#include <openssl/ec.h>
#include <openssl/evp.h>
#include <openssl/x509.h>
EC_KEY* generate_keypair() {
EC_KEY *eckey = EC_KEY_new();
EC_GROUP *ecgroup = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
EC_KEY_set_group(eckey, ecgroup);
EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE);
int kpGenerationStatus = EC_KEY_generate_key(eckey);
if (kpGenerationStatus) {
return eckey;
}
return nullptr;
}
int main()
{
EC_GROUP *ecgroup = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
EC_KEY *keypair = generate_keypair();
BIO* out = BIO_new(BIO_s_mem());
BIO* b64 = BIO_new(BIO_f_base64());
BIO_push(b64, out);
i2d_EC_PUBKEY_bio(b64, keypair);
BIO_flush(b64);
// do what you want this the output in out memory BIO
char* p;
long length = BIO_get_mem_data(out, &p);
// ensure null terminated but copying the buffer into a string to output...
puts(std::string(p, length).c_str());
BIO_free_all(out);
}
I can't complete on the Java side, but if it works with the manual openssl generated base64 string then it will work with the sample application.
I've to convert an old c++ project in nodejs. That project relies in sha2 (polarssl) to do some cryptography. I tried to do this using crypto but I failed since the outputs are completely different.
//here i declare 2 keys
unsigned char key1[] = {0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F};
unsigned char key2[] = {0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC};
sha2_context sha_ctx;
// Part 1: Compute the key with key1 and key 2
sha2_starts( &sha_ctx, 0 );
sha2_update( &sha_ctx, key1, sizeof(key1) );
sha2_update( &sha_ctx, key2, sizeof(key2) );
sha2_finish( &sha_ctx, digest );
// Part 2: The HMAC SHA-2 HMAC start
sha2_hmac_starts( &sha_ctx, digest, 32, 0 );
// SHA-2 Update
sha2_hmac_update( &sha_ctx, buffer, 16 );
// SHA-2 Finish
sha2_hmac_finish( &sha_ctx, digest );
Here's my attempts:
Using crypto HMAC (I tried it even if I thought it was not the correct way)
var {key1, key2, key_expected, key_expected_hex} = common;
// They use http://asf.atmel.com/docs/latest/uc3c/html/sha2_8h.html
function test(){
var hmac = crypto.createHmac('SHA256', new Buffer([0x00]))
hmac.update(key1);
hmac.update(key2);
var r = hmac.digest('hex');
console.log({
output: r,
expected: key_expected_hex
})
return r === key_expected_hex;
}
Using npm 'sha2' library
const {SHA256} = require("sha2");
function test(){
var hmac = SHA256(key1);
hmac = SHA256(key2);
console.log(hmac);
var r = hmac.toString('hex');;
console.log({
output: r,
expected: key_expected_hex
})
return r === key_expected_hex;
}
Can someone help me out pointing me in the right direction?
In node.js the Part 1 consisting of computing the key for the hmac used in Part 2, should not use hmac but only sha256 as in the C++ code :
const crypto = require('crypto');
const key1 = new Buffer([0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F]);
const key2 = new Buffer([0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC]);
// Part 1: Compute the key from key1 and key2
var h = crypto.createHash('sha256');
h.update(key1);
h.update(key2);
var keyForHmac = h.digest();
console.log('key: ' + keyForHmac.toString('hex'));
// Part 2: The HMAC SHA-256
var buffer = new Buffer([/* data to be HMACed */]);
var hmac = crypto.createHmac('sha256', keyForHmac);
hmac.update(buffer);
var hmacDigest = hmac.digest();
console.log('hmac: ' + hmacDigest.toString('hex'));
I have to get ECDSA signature in variable using Crypto++.
I tried to get it after launching SignMessage but signature is empty.
How could i get it?
Have you had a look at the Crypto++ wiki? There's a lot of stuff on Elliptic Curve Digital Signature Algorithm.
Its not really clear what you are doing or where things went wrong, so here's a copy and paste from the wiki:
Signing:
ECDSA<ECP, SHA1>::PrivateKey privateKey;
privateKey.Load(...);
AutoSeededRandomPool prng;
string message = "Yoda said, Do or do not. There is no try.";
string signature;
StringSource ss1( message, true /*pump all*/,
new SignerFilter( prng,
ECDSA<ECP,SHA1>::Signer( privateKey ),
new StringSink( signature )
) // SignerFilter
); // StringSource
Verification:
ECDSA<ECP, SHA1>::PublicKey publicKey;
publicKey.Load(...);
// Result of the verification process
bool result = false;
// Exactly what was signed in the previous step
string message = ...;
// Output from the signing operation in the previous step
string signature = ...;
StringSource ss2( signature+message, true /*pump all*/,
new SignatureVerificationFilter(
ECDSA<ECP,SHA1>::Verifier(publicKey),
new ArraySink( (byte*)&result, sizeof(result) )
) // SignatureVerificationFilter
);
// Verification failure?
if( !result ) {...}
If you would like the verifcation to throw on a failure, then try:
static const int VERIFICATION_FLAGS = SIGNATURE_AT_BEGIN | THROW_EXCEPTION;
StringSource ss3( signature+message, true /*pump all*/,
new SignatureVerificationFilter(
ECDSA<ECP,SHA1>::Verifier(publicKey),
NULL, /* No need for attached filter */
VERIFICATION_FLAGS
) // SignatureVerificationFilter
);
What I'm trying to do is generate random RSA keys and then store them before my program terminates. This part is working just fine using RSA_generate_key, PEM_write_bio_RSAPrivateKey and PEM_write_bio_RSA_PUBKEY. I can also encrypt/decrypt just find using the RSA structure returned by RSA_generate_key.
However, my problem comes when my program restarts and I want to read back in the keys that I stored previously. I can use PEM_read_bio_RSAPrivateKey and PEM_read_bio_RSA_PUBKEY to pull the keys in, but I need to get them into the same RSA structure, similar to how they are stored by RSA_generate_key.
My code is shown below. I have the keys stored in memory along with a small header that tell me how large the keys are. The private key start right after the header and the public key is stored right after the private key.
privateKey = (uint8_t *) ( buffer + rsaStruct->hdrSize );
publicKey = (uint8_t *) ( privateKey + rsaStruct->privateKeyLength );
bioPrivate = BIO_new_mem_buf( (void *) privateKey, rsaStruct->privateKeyLength );
bioPublic = BIO_new_mem_buf( (void *) publicKey, rsaStruct->publicKeyLength );
bioPrivate = BIO_new_mem_buf( (void *) privateKey, rsaStruct->privateKeyLength + rsaStruct->publicKeyLength );
if( bioPrivate == NULL || bioPublic == NULL ) {
fprintf( stderr, "%s: BIO_new_mem_buf failed!\n", __FUNCTION__ );
return ECE_RSA_ERROR_BIO_CREATION_FAILED;
}
PEM_read_bio_RSAPrivateKey( bioPrivate, &keyPair, NULL, NULL );
PEM_read_bio_RSA_PUBKEY( bioPublic, &keyPair, NULL, NULL );
BIO_free( bioPrivate );
BIO_free( bioPublic );
If I try to just send in the same RSA structure, it doesn't seem to work. I'm able to encrypt just fine, but my decryption fails. This could likely be due to the fact that the public key is the last key retrieve and the one used for encryption. If the second call over-writes the address of my RSA struct, I would end up with an RSA structure that has nothing but the public key.
Anyway, if anyone could tell me how to get both the public and private key into the same RSA structure, that would be great!
Comparing to RSA private key, public key additionaly contains only the public exponent. So just copy it from public key to private key structure, and everything should work.