Convert c# Rfc2898DeriveBytes code in java - java

I am trying to reproduce the following encryption/decryption algorithm in Java, but I can't find the alternatives for multiple methods such as Rfc2898DeriveBytes().
How do I do this?
Code in c#:
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
namespace myCompany.Entities.Configuration
{
public static class VideoSourceCryptoHelper
{
private const string EncryptionKey = "MyWord";
private static readonly byte[] Salt = {0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76};
private const string ErrorText = "***ERROR***";
**public static string Encrypt(string encryptString, bool suppressException = false)**
{
if (string.IsNullOrEmpty(encryptString))
{
return string.Empty;
}
try
{
var clearBytes = Encoding.Unicode.GetBytes(encryptString);
using (var encryption = Aes.Create())
{
var pdb = new Rfc2898DeriveBytes(EncryptionKey, Salt);
encryption.Key = pdb.GetBytes(32);
encryption.IV = pdb.GetBytes(16);
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, encryption.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(clearBytes, 0, clearBytes.Length);
}
encryptString = Convert.ToBase64String(ms.ToArray());
}
}
}
catch(Exception)
{
if (suppressException)
return ErrorText;
else
throw;
}
return encryptString;
}
Can anyone give similar code in java that will do what C# does?
The "duplicate" answer shows how to write the decrypt method, but I need the encrypt method, as I wrote above.

Related

Android Java - Encrypting String using a RSA public key .PEM

I have an RSA public key certificate. I can use the file that has a .PEM extension or simply use it as a String which has the following format:
-----BEGIN RSA PUBLIC KEY-----
{KEY}
-----END RSA PUBLIC KEY-----
I am trying to use this key in order to send an encrypted JSON to the server. I tried numerous solutions from other related stack overflow questions, but none of the answers didn't for me. This answer seems to makes sense https://stackoverflow.com/a/43534042, but something doesn't work properly, maybe it's because X509EncodedKeySpec expects DER encoded data not PEM according to one of the comments. But in this case what should i use for PEM encoded data?
As already commented by #Topaco your RSA Public Key is in PEM encoding but in PKCS#1 format and not in PKCS#8 format that is readable by Java "out of the box".
The following solution was provided by #Maarten Bodewes here on SO (https://stackoverflow.com/a/54246646/8166854) will do the job to read and transform it to a (Java) usable RSAPublicKey.
The solution is running on my OpenJdk11, if your'e using "Android Java" you may have to change the Base64-calls. There are no external libraries like Bouncy Castle necessary. Please obey the notes from Maarten regarding key lengths.
The simple output:
Load RSA PKCS#1 Public Keys
pkcs1PublicKey: Sun RSA public key, 2048 bits
params: null
modulus: 30333480050529072539152474433261825229175303911986187056546130987160889422922632165228273249976997833741424393377152058709551313162877595353675051556949998681388601725684016724167050111037861889500002806879899578986908702627237884089998121288607696752162223715667435607286689842713475938751449494999920670300421827737208147069624343973533326291094315256948284968840679921633097541211738122424891429452073949806872319418453594822983237338545978675594260211082913078702997218079517998196340177653632261614031770091082266225991043014081642881957716572923856737534043425399435601282335538921977379429228634484095086075971
public exponent: 65537
code:
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
public class LoadPkcs1PublicKeyPemSo {
// solution from https://stackoverflow.com/a/54246646/8166854 answered Jan 18 '19 at 1:36 Maarten Bodewes
private static final int SEQUENCE_TAG = 0x30;
private static final int BIT_STRING_TAG = 0x03;
private static final byte[] NO_UNUSED_BITS = new byte[] { 0x00 };
private static final byte[] RSA_ALGORITHM_IDENTIFIER_SEQUENCE =
{(byte) 0x30, (byte) 0x0d,
(byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x01,
(byte) 0x05, (byte) 0x00};
public static void main(String[] args) throws GeneralSecurityException, IOException {
System.out.println("Load RSA PKCS#1 Public Keys");
String rsaPublicKeyPem = "-----BEGIN RSA PUBLIC KEY-----\n" +
"MIIBCgKCAQEA8EmWJUZ/Osz4vXtUU2S+0M4BP9+s423gjMjoX+qP1iCnlcRcFWxt\n" +
"hQGN2CWSMZwR/vY9V0un/nsIxhZSWOH9iKzqUtZD4jt35jqOTeJ3PCSr48JirVDN\n" +
"Let7hRT37Ovfu5iieMN7ZNpkjeIG/CfT/QQl7R+kO/EnTmL3QjLKQNV/HhEbHS2/\n" +
"44x7PPoHqSqkOvl8GW0qtL39gTLWgAe801/w5PmcQ38CKG0oT2gdJmJqIxNmAEHk\n" +
"atYGHcMDtXRBpOhOSdraFj6SmPyHEmLBishaq7Jm8NPPNK9QcEQ3q+ERa5M6eM72\n" +
"PpF93g2p5cjKgyzzfoIV09Zb/LJ2aW2gQwIDAQAB\n" +
"-----END RSA PUBLIC KEY-----";
RSAPublicKey pkcs1PublicKey = getPkcs1PublicKeyFromString(rsaPublicKeyPem);
System.out.println("pkcs1PublicKey: " + pkcs1PublicKey);
}
public static RSAPublicKey getPkcs1PublicKeyFromString(String key) throws GeneralSecurityException {
String publicKeyPEM = key;
publicKeyPEM = publicKeyPEM.replace("-----BEGIN RSA PUBLIC KEY-----", "");
publicKeyPEM = publicKeyPEM.replace("-----END RSA PUBLIC KEY-----", "");
publicKeyPEM = publicKeyPEM.replaceAll("[\\r\\n]+", "");
byte[] pkcs1PublicKeyEncoding = Base64.getDecoder().decode(publicKeyPEM);
return decodePKCS1PublicKey(pkcs1PublicKeyEncoding);
}
/*
solution from https://stackoverflow.com/a/54246646/8166854 answered Jan 18 '19 at 1:36 Maarten Bodewes
The following code turns a PKCS#1 encoded public key into a SubjectPublicKeyInfo encoded public key,
which is the public key encoding accepted by the RSA KeyFactory using X509EncodedKeySpec -
as SubjectPublicKeyInfo is defined in the X.509 specifications.
Basically it is a low level DER encoding scheme which
wraps the PKCS#1 encoded key into a bit string (tag 0x03, and a encoding for the number of unused
bits, a byte valued 0x00);
adds the RSA algorithm identifier sequence (the RSA OID + a null parameter) in front -
pre-encoded as byte array constant;
and finally puts both of those into a sequence (tag 0x30).
No libraries are used. Actually, for createSubjectPublicKeyInfoEncoding, no import statements are even required.
Notes:
NoSuchAlgorithmException should probably be caught and put into a RuntimeException;
the private method createDERLengthEncoding should probably not accept negative sizes.
Larger keys have not been tested, please validate createDERLengthEncoding for those -
I presume it works, but better be safe than sorry.
*/
public static RSAPublicKey decodePKCS1PublicKey(byte[] pkcs1PublicKeyEncoding)
throws NoSuchAlgorithmException, InvalidKeySpecException
{
byte[] subjectPublicKeyInfo2 = createSubjectPublicKeyInfoEncoding(pkcs1PublicKeyEncoding);
KeyFactory rsaKeyFactory = KeyFactory.getInstance("RSA");
RSAPublicKey generatePublic = (RSAPublicKey) rsaKeyFactory.generatePublic(new X509EncodedKeySpec(subjectPublicKeyInfo2));
return generatePublic;
}
public static byte[] createSubjectPublicKeyInfoEncoding(byte[] pkcs1PublicKeyEncoding)
{
byte[] subjectPublicKeyBitString = createDEREncoding(BIT_STRING_TAG, concat(NO_UNUSED_BITS, pkcs1PublicKeyEncoding));
byte[] subjectPublicKeyInfoValue = concat(RSA_ALGORITHM_IDENTIFIER_SEQUENCE, subjectPublicKeyBitString);
byte[] subjectPublicKeyInfoSequence = createDEREncoding(SEQUENCE_TAG, subjectPublicKeyInfoValue);
return subjectPublicKeyInfoSequence;
}
private static byte[] concat(byte[] ... bas)
{
int len = 0;
for (int i = 0; i < bas.length; i++)
{
len += bas[i].length;
}
byte[] buf = new byte[len];
int off = 0;
for (int i = 0; i < bas.length; i++)
{
System.arraycopy(bas[i], 0, buf, off, bas[i].length);
off += bas[i].length;
}
return buf;
}
private static byte[] createDEREncoding(int tag, byte[] value)
{
if (tag < 0 || tag >= 0xFF)
{
throw new IllegalArgumentException("Currently only single byte tags supported");
}
byte[] lengthEncoding = createDERLengthEncoding(value.length);
int size = 1 + lengthEncoding.length + value.length;
byte[] derEncodingBuf = new byte[size];
int off = 0;
derEncodingBuf[off++] = (byte) tag;
System.arraycopy(lengthEncoding, 0, derEncodingBuf, off, lengthEncoding.length);
off += lengthEncoding.length;
System.arraycopy(value, 0, derEncodingBuf, off, value.length);
return derEncodingBuf;
}
private static byte[] createDERLengthEncoding(int size)
{
if (size <= 0x7F)
{
// single byte length encoding
return new byte[] { (byte) size };
}
else if (size <= 0xFF)
{
// double byte length encoding
return new byte[] { (byte) 0x81, (byte) size };
}
else if (size <= 0xFFFF)
{
// triple byte length encoding
return new byte[] { (byte) 0x82, (byte) (size >> Byte.SIZE), (byte) size };
}
throw new IllegalArgumentException("size too large, only up to 64KiB length encoding supported: " + size);
}
}
Michael Fehr's answer shows how to load a public key in PKCS#1 format without third party libraries. If the latter is a requirement, then that's the way you have to go.
Otherwise, if you use BouncyCastle, there are much less elaborate solutions that might also be considered and are therefore worth mentioning (although the given answer is already accepted):
The following method expects a public key in PKCS#1 format, PEM encoded and loads it into a java.security.PublicKey instance:
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import java.security.PublicKey;
import java.io.StringReader;
...
private static PublicKey getPublicKey(String publicKeyc) throws Exception {
PEMParser pemParser = new PEMParser(new StringReader(publicKeyc));
JcaPEMKeyConverter jcaPEMKeyConverter = new JcaPEMKeyConverter();
SubjectPublicKeyInfo subjectPublicKeyInfo = (SubjectPublicKeyInfo)pemParser.readObject();
PublicKey publicKey = jcaPEMKeyConverter.getPublicKey(subjectPublicKeyInfo);
return publicKey;
}
Another similarly compact implementation can be found here.
To use BouncyCastle in Android, a dependency to BouncyCastle corresponding to the API level used must be referenced in the dependencies section of the build.gradle file. I used API Level 28 (Pie) and referenced the following dependency (assuming Android Studio):
implementation 'org.bouncycastle:bcpkix-jdk15on:1.65'

BouncyCastle ECDSA Signature Verification Failed Using prime256v1 and SHA256withECDSA Algorithm

I need to verify an ECDSA signature with Java using BouncyCastle crypto provider. So far BouncyCastle failed to verify the signature.
The signature is created in Atmel AT88CK590 Crypto Authentication module and Public key can be obtained out from the module. Here is the Public Key, in C/C++ format, of 64 octets long:
uint8_t pubKey[] = {
// X coordinate of the elliptic curve.
0xc1, 0x71, 0xCB, 0xED, 0x65, 0x71, 0x82, 0x2E, 0x8F, 0x8A, 0x43, 0x8D, 0x72, 0x56, 0xD1, 0xC8,
0x86, 0x3C, 0xD0, 0xBC, 0x7F, 0xCC, 0xE3, 0x6D, 0xE7, 0xB7, 0x17, 0xED, 0x29, 0xC8, 0x38, 0xCB,
// Y coordinate of the elliptic curve.
0x80, 0xCD, 0xBE, 0x0F, 0x1D, 0x5C, 0xC5, 0x46, 0x99, 0x24, 0x8F, 0x6E, 0x0A, 0xEA, 0x1F, 0x7A,
0x43, 0xBA, 0x2B, 0x03, 0x80, 0x90, 0xE9, 0x25, 0xB2, 0xD0, 0xE6, 0x48, 0x93, 0x91, 0x64, 0x83
};
The original message, the signature and Public key in Base64 encoding:
// Raw message to sign
private static final String tokenStr = "12345678901234567890123456789012";
// Base64 encoded
private static final String pubKeyStr = "wXHL7WVxgi6PikONclbRyIY80Lx/zONt57cX7SnIOMuAzb4PHVzFRpkkj24K6h96
Q7orA4CQ6SWy0OZIk5Fkgw==";
// Base64 encoded
private static final String signatureStr = "XF2WossFTA82ndYFGEH0FPqAldkFQLGd/Bv/Qh8UYip7sXUvCUnFgi1YXjN3WxLn
IwSo3OaHLCOzGAtIis0b3A==";
To convert the Public key I am using the following:
private static PublicKey getPublicKeyFromBytes(byte[] pubKey, String ecSpec, String provider)
throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException {
ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec(ecSpec);
KeyFactory kf = KeyFactory.getInstance(ECDSA_CRYPTO, provider);
ECNamedCurveSpec params = new ECNamedCurveSpec(ecSpec, spec.getCurve(), spec.getG(), spec.getN());
ECPoint pubPoint = ECPointUtil.decodePoint(params.getCurve(), pubKey);
ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(pubPoint, params);
PublicKey publicKey = kf.generatePublic(pubKeySpec);
return publicKey;
}
To convert the signature to DER format I am using the following:
private static byte[] toDERSignature(byte[] tokenSignature) throws IOException {
byte[] r = Arrays.copyOfRange(tokenSignature, 0, tokenSignature.length / 2);
byte[] s = Arrays.copyOfRange(tokenSignature, tokenSignature.length / 2, tokenSignature.length);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
DEROutputStream derOutputStream = new DEROutputStream(byteArrayOutputStream);
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(new ASN1Integer(new BigInteger(1, r)));
v.add(new ASN1Integer(new BigInteger(1, s)));
derOutputStream.writeObject(new DERSequence(v));
byte[] derSignature = byteArrayOutputStream.toByteArray();
return derSignature;
}
Here is the code to verify the signature:
Security.addProvider(new BouncyCastleProvider());
byte[] tokenBytes = tokenStr.getBytes("UTF-8");
String urlDecodePubKeyStr = pubKeyStr.replace(newlineHtml, "");
byte[] pubKeyBytes = DatatypeConverter.parseBase64Binary(urlDecodePubKeyStr);
String urlDecodeSignatureStr = signatureStr.replace(newlineHtml, "");
byte[] signBytes = DatatypeConverter.parseBase64Binary(urlDecodeSignatureStr);
byte[] derSignature = toDERSignature(signBytes);
ByteBuffer bb = ByteBuffer.allocate(pubKeyBytes.length + 1);
bb.put((byte)4);
bb.put(pubKeyBytes);
PublicKey ecPublicKey = getPublicKeyFromBytes(bb.array(), "prime256v1", "BC");
System.out.println("\nSignature: " + Hex.toHexString(signBytes).toUpperCase());
System.out.println("DER Signature: " + Hex.toHexString(derSignature).toUpperCase());
System.out.println(ecPublicKey.toString());
Signature signature = Signature.getInstance("SHA256withECDSA", "BC");
signature.initVerify(ecPublicKey);
signature.update(tokenBytes);
boolean result = signature.verify(derSignature);
System.out.println("BC Signature Valid: " + result);
The output:
Signature: 5C5D96A2CB054C0F369DD6051841F414FA8095D90540B19DFC1BFF421F14622A7BB1752F0949C5822D585E33775B12E72304A8DCE6872C23B3180B488ACD1BDC
DER Signature: 304402205C5D96A2CB054C0F369DD6051841F414FA8095D90540B19DFC1BFF421F14622A02207BB1752F0949C5822D585E33775B12E72304A8DCE6872C23B3180B488ACD1BDC
EC Public Key
X: c171cbed6571822e8f8a438d7256d1c8863cd0bc7fcce36de7b717ed29c838cb
Y: 80cdbe0f1d5cc54699248f6e0aea1f7a43ba2b038090e925b2d0e64893916483
BC Signature Valid: false
Have anyone run into the same problem before? What did I miss here?
That signature value is not computed on the hash as is standard and usual, but directly on the data. Either:
the Atmel doesn't hash so your could must hash first and supply the hash otuput to be signed
the Atmel should hash but you didn't set some necessary option or something
you actually want an unconventional 'raw' signature with no hash. Note this limits the data to 32 or maybe 31 bytes. And if the values to be signed can be affected by an adversary and the random generator used for signing is weak, I think that gives an attack that recovers your privatekey (although I haven't worked through it). Even with the if's that's a risk I would avoid.
At any rate, the value you have can be verified using scheme NoneWithECDSA.
In addition, in testing this I found some possible improvements in your code that you may or may not want. First, you don't need to quasi-encode and then decode the point, given you have X,Y in fixed format you can just use them. Second, you do need to DER-encode the signature, but it can be done more simply. Here's my version, with both changes, in a single linear block for clarity:
public static void main (String[] args) throws Exception {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
// test data; real data would come from outside
byte[] dataBytes = "12345678901234567890123456789012".getBytes("UTF-8");
String sigString = "XF2WossFTA82ndYFGEH0FPqAldkFQLGd/Bv/Qh8UYip7sXUvCUnFgi1YXjN3WxLn
IwSo3OaHLCOzGAtIis0b3A==";
String pubkeyString = "wXHL7WVxgi6PikONclbRyIY80Lx/zONt57cX7SnIOMuAzb4PHVzFRpkkj24K6h96
Q7orA4CQ6SWy0OZIk5Fkgw==";
String ecSpec="prime256v1"; int size=32; // bytes for x,y in pubkey also r,s in sig
byte[] pubkeyBytes = DatatypeConverter.parseBase64Binary(pubkeyString.replaceAll("
","") );
KeyFactory kf = KeyFactory.getInstance ("ECDSA", "BC");
ECNamedCurveParameterSpec cspec = ECNamedCurveTable.getParameterSpec(ecSpec);
BigInteger x = new BigInteger(1, Arrays.copyOfRange(pubkeyBytes,0,size));
BigInteger y = new BigInteger(1, Arrays.copyOfRange(pubkeyBytes,size,size*2));
ECPublicKeySpec kspec = new ECPublicKeySpec (cspec.getCurve().createPoint(x, y), cspec);
PublicKey k = kf.generatePublic(kspec);
byte[] sigBytes = DatatypeConverter.parseBase64Binary(sigString.replaceAll("
","") );
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(/*r*/new ASN1Integer(new BigInteger(1, Arrays.copyOfRange(sigBytes,0,size))));
v.add(/*s*/new ASN1Integer(new BigInteger(1, Arrays.copyOfRange(sigBytes,size,size*2))));
byte[] sigDer = new DERSequence(v).getEncoded();
Signature sig = Signature.getInstance("NoneWithECDSA", "BC"); // NOTE None instead of a hash
sig.initVerify (k); sig.update (dataBytes);
System.out.println ("verify="+sig.verify(sigDer));
}
PS: you comment the publickey halves as X [Y] coordinate of the elliptic curve. They are coordinates of the point on the curve which is the publickey; the curve itself doesn't have coordinates.

convert Encryption Algo from C# to Java

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.

How to decrypt text encrypted in PHP in Java (mcrypt_rijndael_256)

I am having some problems decrypting some text sent from PHP in Java. I have already written code that does this for a windows version of the program in C# but I am unfamiliar with Java so this might be more simple than I am making it.
The encryption code in PHP:
function encryptString($plain)
{
$iv = "12347112549354892543218565456541";
$ftpSalt = "hjjuoelkdploida";
$block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
$padding = $block - (strlen($plain) % $block);
$plain .= str_repeat(chr($padding), $padding);
$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $ftpSalt, $plain, MCRYPT_MODE_CBC, $iv);
$crypttext64 = base64_encode($crypttext);
return $crypttext64;
}
The C# function that decrypts:
static public String doDecryptRJ256(string cypher)
{
var sRet = "";
var cypherByte = Decode(cypher);
var encoding = new UTF8Encoding();
var Key = encoding.GetBytes(mKey);
var IV = encoding.GetBytes(mIv);
using (var rj = new RijndaelManaged())
{
try
{
rj.Padding = PaddingMode.PKCS7;
rj.Mode = CipherMode.CBC;
rj.KeySize = 256;
rj.BlockSize = 256;
rj.Key = Key;
rj.IV = IV;
var ms = new MemoryStream(cypherByte);
using (var cs = new CryptoStream(ms, rj.CreateDecryptor(Key, IV), CryptoStreamMode.Read))
{
using (var sr = new StreamReader(cs))
{
sRet = sr.ReadLine();
}
}
}
finally
{
rj.Clear();
}
}
return sRet;
}
}
I have tried various suggestions from the internet but not found any that actually work. THe latest suggestion I tried to another answer was:
byte[] cipherText = encryptedText.getBytes("UTF-8");
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
SecretKeySpec key = new SecretKeySpec(KEY.getBytes("UTF-8"), "AES");
cipher.init(Cipher.DECRYPT_MODE, key,new IvParameterSpec(IV.getBytes("UTF-8")));
return new String(cipher.doFinal(cipherText),"UTF-8");
I know similar questions have been asked previously but the solutions (possibly due to my own ignorance) haven't helped me to get this working. I haven't done any encryption work before so there is probably something that I am just not getting.
The code to encrypt and decrypt are within my control so if someone wants to suggest an alternative method for all three languages I am open to changing the encryption method.

Decrypt ( with PHP ) a Java encryption ( PBEWithMD5AndDES )

Someone asked me to decrypt with PHP a string encrypted with the following Java Class.
public class CryptoLibrary {
private Cipher encryptCipher;
private sun.misc.BASE64Encoder encoder = new sun.misc.BASE64Encoder();
public CryptoLibrary() throws SecurityException{
java.security.Security.addProvider(new com.sun.crypto.provider.SunJCE());
char[] pass = "NNSHHETJKKSNKH".toCharArray();
byte[] salt = {
(byte) 0xa3, (byte) 0x21, (byte) 0x24, (byte) 0x2c,
(byte) 0xf2, (byte) 0xd2, (byte) 0x3e, (byte) 0x19 };
init(pass, salt, iterations);
}
public void init(char[] pass, byte[] salt, int iterations)throws SecurityException{
PBEParameterSpec ps = new javax.crypto.spec.PBEParameterSpec(salt, 20);
SecretKeyFactory kf = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey k = kf.generateSecret(new javax.crypto.spec.PBEKeySpec(pass));
encryptCipher = Cipher.getInstance("PBEWithMD5AndDES/CBC/PKCS5Padding");
encryptCipher.init(Cipher.ENCRYPT_MODE, k, ps);
}
}
public synchronized String encrypt(String str) throws SecurityException{
if(str!=null){
byte[] utf8 = str.getBytes("UTF8");
byte[] enc = encryptCipher.doFinal(utf8);
return encoder.encode(enc);
}
else {
return null;
}
}
}
I don't know any Java so I need some help to understand this encryption.
1) what is the meaning of this line?
PBEParameterSpec ps = new javax.crypto.spec.PBEParameterSpec(salt,20);
2) what value should I use for the first parameter of
string mcrypt_encrypt ( string $cipher , string $key , string $data , string $mode [, string $iv ] )
3) When should I use MD5 in my php script?
I had to do the same thing for a customer of mine and wrote a few lines of code to help with issue: https://github.com/kevinsandow/PBEWithMD5AndDES
1) It creates the parameters for Password Based Encryption, the salt, which is included in the hash calculations, and the number of iterations that the hash method is executed (on it's own output). It is used to defeat rainbow table attacks, basically an attacker has to go through the same number of iterations to check if the password is correct, and he cannot use a precalculated table because the salt will be different for each password (so you cannot see if somebody has the same password as another user).
2) MCRYPT_DES, and you will need MCRYPT_MODE_CBC for the mode, and PKCS#5 padding of course.
3) Only when you are absolutely sure that its weaknesses are not exposed or when absolutely required for compatibility. Fortunately, it is relatively secure for key derivation functions. Download a pbkdf1 method for PHP and put it in there - if not already included.

Categories