Is it possible to use RSAwithSHA1 in php? [duplicate] - java

I'm trying to implement digital signature in php as in java sample code below:
Signature rsaSig = Signature.getInstance("MD5withRSA");
RSAPrivateKey clientPrivateKey = readPrivateKeyFromFile(fileName);
rsaSig.initSign(clientPrivateKey);
String source = msg;
byte temp[] = source.getBytes();
rsaSig.update(temp);
byte sig[] = rsaSig.sign();
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(sig);
My php code :
$rsa = new Crypt_RSA();
$rsa->loadKey('...'); // in xml format
$plaintext = '...';
$rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
$signature = $rsa->sign($plaintext);
But looks like some thing is missing. We should get same signature as java code returns.Can anybody guide me in this?

By default phpseclib uses sha1 as the hash. You probably need to do $rsa->setHash('md5').

Related

ECDSA signature generation KeyPair Java to C# - JcaPEMKeyConverter()

I have been converting over some code from a Java Android app to C# using Xamarin and I have come across a problem when trying to generate a signature using a certain snippet of BouncyCastle code.
Is there a replacement function in C# for the line of code
"pair = new JcaPEMKeyConverter().getKeyPair((PEMKeyPair) parsed);" ??
This is the Java code:
// Generating the signature
Signature signature = Signature.getInstance("SHA256withECDSA");
Reader rdr = new StringReader("privatekeygoeshere");
Object parsed = new PEMParser(rdr).readObject();
KeyPair pair;
pair = new JcaPEMKeyConverter().getKeyPair((PEMKeyPair) parsed);
PrivateKey signingKey = pair.getPrivate();
signature.initSign(signingKey);
signature.update(nonceData1);
signature.update(nonceData2);
signature.update(collectorID);
signature.update(publicKeyCompressed);
byte[] signedData = signature.sign();
I have found another way to read the private key and create a KeyPair. However, the private key is stored as a AsymmetricCipherKeyPair which I cannot add into the signature.InitSign() function as this requires an IPrivateKey.
The Different ways that I have tried to create a signature do not allow me to update other byte array data to the signature generation like the Java code, this doesn't work for me so I am really stuck.
I am also open to any ideas of signature generation.
Example of this here:
AsymmetricKeyParameter signingKey;
AsymmetricCipherKeyPair keyPair = null;
using (var textReader = new System.IO.StringReader("privatekeygoeshere"))
{
// Only a private key
Org.BouncyCastle.OpenSsl.PemReader pemReader = new Org.BouncyCastle.OpenSsl.PemReader(textReader);
keyPair = pemReader.ReadObject() as AsymmetricCipherKeyPair;
signingKey = keyPair.Private;
}
I managed to come up with a solution for my problem using a string reader and looping through each array using the Update() command. This works well for me however, if any one can find a better way of doing this... Please comment below.
AsymmetricKeyParameter signingKey;
using (var textReader = new System.IO.StringReader(LONG_TERM_PRIVATE_KEY))
{
// Only a private key
Org.BouncyCastle.OpenSsl.PemReader pemReader = new Org.BouncyCastle.OpenSsl.PemReader(textReader);
keyPair = pemReader.ReadObject() as AsymmetricCipherKeyPair;
signingKey = keyPair.Private;
}
var signer = SignerUtilities.GetSigner("SHA256withECDSA");
signer.Init(true, signingKey);
foreach (byte b in terminalNonce)
{
signer.Update(b);
}
foreach (byte b in mobileDeviceNonce)
{
signer.Update(b);
}
foreach (byte b in COLLECTOR_ID)
{
signer.Update(b);
}
foreach (byte b in terminalEphemeralPublicKeyCompressed)
{
signer.Update(b);
}
var signed = signer.GenerateSignature();

Java Digital Signature does not match C# (SHA1withRSA)

So I am not the Crypto wizard by any means but here is some code I have that works in C# but does not return the same b64 string in Java.
c#
string _Cert = "long b64 string here";
string _Pass = "my password";
string lvreturn = "Test";
byte[] lvCertBytes = Convert.FromBase64String(_Cert);
X509Certificate2 lvCertFromBytes = new X509Certificate2(lvCertBytes, _Pass);
SHA1Managed lvSHA1 = new SHA1Managed();
byte[] lvData = Encoding.Unicode.GetBytes(lvReturn);
byte[] lvHash = lvSHA1.ComputeHash(lvData);
RSACryptoServiceProvider lvCryptoProvider = (RSACryptoServiceProvider)lvCertFromBytes.PrivateKey;
byte[] lvSignedBytes = lvCryptoProvider.SignHash(lvHash, CryptoConfig.MapNameToOID("SHA1"));
string lvToken = Convert.ToBase64String(lvSignedBytes);
Java
String certB64 = "long b64 string here";
char[] Pass = "text password".toCharArray();
String alias = "guid looking ID here";
String plaintext = "Test";
byte[] certbytes = Base64.getDecoder().decode(certB64);
InputStream in = new ByteArrayInputStream(certbytes);
KeyStore keystore = KeyStore.getInstance("PKCS12");
keystore.load(in,Pass);
KeyStore.PrivateKeyEntry pvk = (KeyStore.PrivateKeyEntry)keystore.getEntry(alias, new KeyStore.PasswordProtection(Pass));
PrivateKey pkey = (PrivateKey)pvk.getPrivateKey();
Signature rsa = Signature.getInstance("SHA1withRSA");
rsa.initSign(pkey);
rsa.update(plaintext.getBytes());
System.out.println("Hash: " + Base64.getEncoder().encodeToString(rsa.sign()));
I have Cert.pfx file that I want to use to use the privatekey to encrypt a https auth segment. I am just ripping the file to a base64 string and stuffing it into the "_Cert" var in C#. I do the same in Java. I want to sign the plaintext message using the private key of the cert and SHA1. The C# code below works and the https server provides a response. Java however is not spitting out the same base64 encoded string. Thanks for some help!
Update: I found a link to another post that is the same as mine but with a couple small diffs, and I didn't want to necro post on it. I followed it exactly removing the messagedigest piece of my original code. I tried reading directly from the pfx file or using the b64 string directly in the code. I am still not getting the same between Java and C#. At this point it has to be something small I am missing with encoding in Java because the C# is basically identical to mine.
Java Digital Signature different to C#

PHP & Java Decrpytion error using PhpSecLib and BouncyCastle

I'm trying to encrypt stuff in java using the public key generated by my PHP:
PHP Code
$rsa = new Crypt_RSA();
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
$rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS1);
$rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
$keys = $rsa->createKey(1024);
extract($keys);
echo (base64_encode($publickey));
For testing purposes, I've set aside a keypair (base64) of the above format.
I retrieve my Public Key in java and base64 decode it.
String publicKeyDecoded = new String(Base64.decode(publicKey));
PEMParser pr = new PEMParser(new StringReader(publicKeyDecoded));
Object obj = pr.readObject();
pr.close();
SubjectPublicKeyInfo spki = (SubjectPublicKeyInfo) obj;
AsymmetricKeyParameter askp = PublicKeyFactory.createKey(spki);
AsymmetricBlockCipher e = new RSAEngine();
e = new org.bouncycastle.crypto.encodings.PKCS1Encoding(e);
e.init(true, askp);
byte[] messageBytes = plainText.getBytes();
byte[] encryptedData = e.processBlock(messageBytes, 0, messageBytes.length);
byte[] encryptedDataBase = Base64.encode(encryptedData);
I send the Base64 encrypted plaintext back to PHP for decryption using the following:
$rsa->loadKey($privatekey) or die ("Cant load");
echo $rsa->decrypt($cipher);
It's unable to decrpyt my encoded message and throws me the error:
Decryption error in <b>/opt/lampp/htdocs/Crypt/RSA.php</b> on line <b>2120</b>
Can someone point me to the right direction? It's been hours since I'm trying to figure this out.
I'm using a hardcoded keypair so I guess there's no question of my keys being wrong...
To answer my own question:
Everything apart from the final decryption PHP was correct.
It should be:
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
$rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS1);
$rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
$rsa->loadKey(base64_decode($_SESSION['private'])) or die ("Cant load");
echo $rsa->decrypt(base64_decode($cipher));
I forgot to un-base64 my encrypted text sent from java and to set the encryption modes.
Thanks neubert.

HMAC a php byte array

I'm trying to integrate a PHP backend with a Java backend. The Java backend expects some credentials which must be correctly encoded and hashed to match at both ends.
The java system converts a string to a sequence of bytes (1), then generates a HMAC/SHA256 keyed hash of that sequence (2) and then base 64 encodes the hash (3).
private static final String HMAC_ALGORITHM = "HmacSHA256";
final SecretKey key = new SecretKeySpec('mysecret', HMAC_ALGORITHM);
final Mac hmac = Mac.getInstance(key.getAlgorithm());
hmac.init(key);
final String stringToHash = "blablabla";
final byte[] bytesToHash = stringToHash.getBytes("UTF8");
final byte[] hash = hmac.doFinal(bytesToHash);
return Base64.encodeBytes(hash);
I can do (1) and convert the string in PHP to a sequence of bytes using
$stringArray = unpack('C*', $string);
// which works and is exactly the same as the Java system at this point
however the second part (2) doesn't seem to match, is there a way to pass a byte array to hmac in PHP because in Java the HMAC method accepts a byte array whereas the PHP one expects a string e.g.
hash_hmac('sha256', $stringArray, $secret);
or do I need to loop through the array and do some magic?
Thanks!
I dont think you need to unpack in php
Just try
hash_hmac('sha256', $string, $secret, TRUE);
Note: I am passing the actual string to the function and the last param raw_output is set to TRUE
Update
Your java code seems to be wrong docs
final SecretKey key = new SecretKeySpec('mysecret', HMAC_ALGORITHM);
This should be like the following
byte[] keyBytes = mysecret.getBytes(); // say mysecret is a String var
final SecretKey key = new SecretKeySpec(keyBytes, HMAC_ALGORITHM);
I have to generate the same Java values on PHP. The only way that it works was this
<?php
$verb = hash_hmac("sha256", "POST" , "9mO6oBVSmb2QTSeN73mEGHHnD", FALSE);
$path = hash_hmac("sha256", '/1.0/benefits/registerBenefit', pack("H*", $verb), FALSE);
$query = hash_hmac("sha256", "" , pack("H*", $path), FALSE);
$body = hash_hmac("sha256", '{"id":"a7d23226-bdfc-4d85-a30a-b2d7eccc36e6","phone_number":"5511973512530","sku":"com.movile.cubes.br.biweekly.homolog","origin":"trade_up_group","application_id":437}' , pack("H*", $query), FALSE);
$rawSignature = hash_hmac("sha256", "x-kiwi-signature", pack("H*", $body), FALSE);
$signature = base64_encode( pack("H*", $rawSignature));
var_dump($signature);
So..I had to use pack("H*", $str) to get the same values that Java was generating.

Interaction between Crypt::RSA (Perl) and java.security.Signature (Java)

I'd like to sign a file by using a RSA keypair. For this purpose I have this Perl script:
#!/usr/bin/perl
use Crypt::RSA;
my $data = ... # File contents
my $rsa = new Crypt::RSA;
my $key = new Crypt::RSA::Key::Private(Filename => "stackoverflow.priv", Password => "*****");
my $signature = $rsa->sign(Message => $data, Key => $key, Armour => 0);
# Write signature to file
On the client side, I'd like to use the following Java function to verify the file:
private static final String PUBLICKEY_MOD = "190343051422614110006523776876348493...";
private static String PUBLICKEY_EXP = "65537";
public boolean check() {
byte[] data = ... // Data
byte[] dataSignature = ... // Signature (as calculated in the Perl script)
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initVerify(getPublicKey());
signature.update(data);
return signature.verify(dataSignature);
}
private PublicKey getPublicKey() {
RSAPublicKeySpec spec = new RSAPublicKeySpec(new BigInteger(PUBLICKEY_MOD), new BigInteger(PUBLICKEY_EXP));
KeyFactory factory = KeyFactory.getInstance("RSA");
return factory.generatePublic(spec);
}
However, check() always reports false. These things I already checked:
data and dataSignature are correctly read
PUBLICKEY_MOD and PUBLICKEY_EXP are correct
getPublicKey() returns a PublicKey which has the correct attributes
the private key and the public key are part of the same pair
Does anyone know how to verify the file correctly? Is signature correctly instanced?
Your first clue that something might be wrong is that you never tell Perl what hash function to use, but you tell Java to use SHA256. You have a lot of work to do on the Perl side. Also, the default padding scheme for Crypt::RSA seems to be PSS, whereas for Java it is PKCSv1.5

Categories

Resources