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
I'm trying to replicate the same signature outcome as the Python code in Java.
Python Code Example:
secret = "1234abcd".encode()
encoded_payload = json.dumps(payload).encode()
b64 = base64.b64encode(encoded_payload)
signature = hmac.new(secret, b64, hashlib.sha384).hexdigest()
Current Java Code (I'm using Apache's Commons Codec for Hex encoding):
String secret = "1234abcd";
String b64 = Base64.getEncoder().encodeToString(payload.toString().getBytes());
Mac hasher = Mac.getInstance("HmacSHA384");
hasher.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA384"));
byte[] hash = hasher.doFinal(b64.getBytes(StandardCharsets.UTF_8));
String signature = Hex.encodeHexString(hash);
How should I go about doing this in Java?
All,I am posting some encrypted xml data(Using AES-128 ) to another application that uses Java to decrypt.When the Java code decrypts the xml,the start tag of the xml is getting truncated and fails validation.I don't have access to their code base .I can decrypt the same data using C# without any data loss.Please see the code I use to encrypt and Decrypt the data . I have researched this and based on the research ,I added the FlushFinalBlocks() and Close() to the CryptoStream in the encryption logic ,but this doesnt seem to fix the issue.
Encryption Code:
public static string Aes128Encrypt(string plainText)
{
string encodedPayload = null;
string base64Iv = null;
string base64Key = null;
byte[] plainBytes = Encoding.UTF8.GetBytes(plainText);
using (RijndaelManaged aesAlg = new RijndaelManaged())
{
aesAlg.KeySize = 128;
aesAlg.Mode = CipherMode.CBC;
aesAlg.Padding = PaddingMode.PKCS7;
aesAlg.BlockSize = 128;
base64Iv = Convert.ToBase64String(aesAlg.IV);
base64Key = Convert.ToBase64String(aesAlg.Key);
// Create a decrytor to perform the stream transform.
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
csEncrypt.Write(plainBytes, 0, plainBytes.Length);
csEncrypt.FlushFinalBlock();
encodedPayload = Convert.ToBase64String(msEncrypt.ToArray());
csEncrypt.Close();
}
msEncrypt.Flush();
msEncrypt.Close();
}
}
return encodedPayload ;
}
Decryption Code:
public static string Aes128Decrypt(string base64Key, string base64IV, string encodedPayload)
{
string plainText = null;
byte[] key = Convert.FromBase64String(base64Key);
byte[] iv = Convert.FromBase64String(base64IV);
byte[] encryptedBytes = Convert.FromBase64String(encodedPayload);
using (RijndaelManaged aesAlg = new RijndaelManaged())
{
aesAlg.KeySize = 128;
aesAlg.Mode = CipherMode.CBC;
aesAlg.BlockSize = 128;
aesAlg.Padding = PaddingMode.PKCS7;
aesAlg.Key = key;
aesAlg.IV = iv;
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(encryptedBytes))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
plainText = srDecrypt.ReadToEnd();
}
}
}
}
return plainText;
}
Testing Code:
string textXml = #"<person>
<firstName>Rennish</firstName>
<lastName>Joseph</lastName>
<accountNumber>12345678910</accountNumber>
<ssn>123456</ssn>
</person>";
Aes128Encrypt(textXml);
string encodedPayload = "4p6uU7SiqB0uCzsrWXMOStP02HM7mKA6QVzcKoNdu3w1+MYLjYVbW/Ig3XPKRRafeu+WKDMuKJJaEREkrZt/Ycvc50wfe2naJ9d0UT5B7Fre1gIsNfZUIK3SF304+WF8zX730mVsluJABKT3JCkk9AkOGCQWPYzcZvH9dojIqGP7V+2j1+IMOPMWWFIitkAi8B7ALxMuMcepzX2/cxHxH7NeID0ytEGUzGfJXSAzQcvBX9dWwUqdMX3Eip5SRPMsotnWWsFTjDuOiZk/q5fuxxWbS6cuYn/64C/vQjEIuheQKn0ZOIDLNPCUavvWD2u6PWNKMNgW/qUIq13W9PQxzIiQxrT7ZqPFJu75C1KdXXUG5lghU7EBAGehHC/5BqFjs9SuYJkV1RrchMEzytrJIQ7Zp4CnOU6Q1rEhFTaMk/s=";
string encodedKey = "2zpVbIxqvjSfJo7zkXzl2A==";
string encodedIV = "5WOQPdmB/BkECmuPdNTaLw==";
Aes128Decrypt(encodedKey, encodedIV, encodedPayload);
Data after encryption at the JAVA application looks like this
<rson>
<firstName>Rennish</firstName>
<lastName>Joseph</lastName>
<accountNumber>12345678910</accountNumber>
<ssn>123456</ssn>
</person>
Interesting problem.
I think the encryption and decryption works fine on both sides.
If part of the encrypted message was lost in transmission you would not be able to decrypt it due to the avalanche effect. So it appears that characters go missing in the plain text.
This might be an encoding issue in the plain text message. The bytes you have encoded and the bytes they decoded are probably the same. The way they are interpreted might not be.
Now there are two options here:
Either <person> becomes <rson> or it becomes rson> and there was a copy-paste mistake.
If the latter case is true then we're missing 3 bytes. This makes me think that the protocol might presume the presence of a byte order marker andsimply removes the first 3 bytes to get rid of it.
If the former case you'd have some very weird encoding issues. As all missing characters appear to be in the ascii range so they shouldn't have these issues.
Easy to test though:
1. Try sending with a byte order marker.
2. Try sending with <XXperson>
3. Try sending some characters with accents and the like.
public static string Encrypt(string KeyToEncrypt)
{
byte[] clearBytes = System.Text.Encoding.Unicode.GetBytes(KeyToEncrypt);
Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(_Pwd, _Salt);
//Calling another private method for Encryption
byte[] encryptedData = Encrypt(clearBytes, pdb.GetBytes(32), pdb.GetBytes(16));
return Convert.ToBase64String(encryptedData);
}
private static byte[] Encrypt(byte[] candelaData, byte[] Key, byte[] IV)
{
MemoryStream ms = new MemoryStream();
CryptoStream cs = null;
Rijndael alg = Rijndael.Create();
alg.Key = Key;
alg.IV = IV;
cs = new CryptoStream(ms, alg.CreateEncryptor(), CryptoStreamMode.Write);
cs.Write(candelaData, 0, candelaData.Length);
cs.FlushFinalBlock();
return ms.ToArray();
}
I want to convert the following algo in java, I have searched for the libraries and couldn't get anything. Help Please. ?
Darab , your best bet in Java has to be Bouncy Castle. You have API's for crypt in salting as well as the AES Rijndael as i read from the code.
For the Rejndael part you can refer : http://www.itcsolutions.eu/2011/08/24/how-to-encrypt-decrypt-files-in-java-with-aes-in-cbc-mode-using-bouncy-castle-api-and-netbeans-or-eclipse/. This gives you a fair idea of the AES part of the code and this question here Rfc2898DeriveBytes in java gives you a great idea of salting and Rfc2898 as well.
Based on nimbus-jose-jwt Java library, I tried to create the following JSON Web Token (JWT) and signed it using a JSON Web Signature (JWS) using a string "secret" hashed to SHA256.
But after generating serialized string and test it at jwt.io, i always get the error "Invalid Signature".
When I try to decode at server side using Python decoder, I also get signature error. What could be wrong?
byte[] bytes = new byte[32];
String message = "secret";
MessageDigest md = MessageDigest.getInstance("SHA-256");
bytes = md.digest(message.getBytes("UTF-8"));
JWSSigner signer = new MACSigner(bytes);
// Prepare JWT with claims set
JWTClaimsSet claimsSet = new JWTClaimsSet();
claimsSet.setSubject("alice");
SignedJWT signedJWT = new SignedJWT(new JWSHeader(JWSAlgorithm.HS256), claimsSet);
// Apply the HMAC
signedJWT.sign(signer);
// To serialize to compact form, produces something like
String s = signedJWT.serialize();
It looks like you are using the SHA-256 digest of "secret" as the key to create the MAC, and plain old "secret" for validating. Replace:
byte[] bytes = new byte[32];
String message = "secret";
MessageDigest md = MessageDigest.getInstance("SHA-256");
bytes = md.digest(message.getBytes("UTF-8"));
JWSSigner signer = new MACSigner(bytes);
with:
JWSSigner signer = new MACSigner("secret");
I am now trying to encode the string using HMAC-SHA256 using Java. The encoded string required to match another set of encoded string generated by Python using hmac.new(mySecret, myPolicy, hashlib.sha256).hexdigest(). I have tried
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
sha256_HMAC.init(secretKey);
byte[] hash = sha256_HMAC.doFinal(policy.getBytes());
byte[] hexB = new Hex().encode(hash);
String check = Hex.encodeHexString(hash);
String sha256 = DigestUtils.sha256Hex(secret.getBytes());
after I print them out, hash, hexB, check and sha256 didn't provide the same result as the following Python encryption method
hmac.new(mySecret, myPolicy, hashlib.sha256).hexdigest()
So, I have try to looking for the library or something that work similar to the above Python function. Can anybody help me out?
Are you sure your key and input are identical and correctly encoded in both java and python?
HMAC-SHA256 works the same on both platforms.
Java
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec("1234".getBytes(), "HmacSHA256");
sha256_HMAC.init(secretKey);
byte[] hash = sha256_HMAC.doFinal("test".getBytes());
String check = Hex.encodeHexString(hash);
System.out.println(new String(check));
Output
24c4f0295e1bea74f9a5cb5bc40525c8889d11c78c4255808be00defe666671f
Python
print hmac.new("1234", "test", hashlib.sha256).hexdigest();
Output
24c4f0295e1bea74f9a5cb5bc40525c8889d11c78c4255808be00defe666671f