admin管理员组文章数量:1313006
Spent almost 2 days with different binations.I am generating a asymmetric key pair (public and private) in java using RSA algorithm and trying to use the public key in javascript to encrypt some text and decrypt back in java on server side. I am getting "javax.crypto.IllegalBlockSizeException: Data must not be longer than 128 bytes" exception while trying to decrypt back the string encrypted in javascript. Would appreciate some help...
Using thi Javascript library to encrypt.
var publicKeyString = ""// base64encoded public key string generated in java
Here is my javascript code
var EncryptionResult = cryptico.encrypt("somestring", publicKeyString);
console.log("Encrypted status-"+EncryptionResult.status);
console.log("Encrypted String-"+EncryptionResult.cipher);
It is successfully encrypting the string.
Java Key Generation and Decryption
Cipher cipher = Cipher.getInstance("RSA");
KeyFactory fact = KeyFactory.getInstance("RSA");
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(1024); // 1024 used for normal
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
FileOutputStream fos = null;
ObjectOutputStream oos = null;
Code to store the private key in file which is used to decrypt in decrypt method.
RSAPrivateKeySpec rsaPrivKeySpec = fact.getKeySpec(privateKey,
RSAPrivateKeySpec.class);
System.out.println("Writing private key...");
fos = new FileOutputStream(PRIVATE_KEY_FILE);
oos = new ObjectOutputStream(new BufferedOutputStream(fos));
oos = new ObjectOutputStream(new BufferedOutputStream(fos));
oos.writeObject(rsaPrivKeySpec.getModulus());
oos.writeObject(rsaPrivKeySpec.getPrivateExponent());
oos.close();
Decrypt method
public String decrypt(String ciphertext)
throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException
{
if (ciphertext.length() == 0) return null;
byte[] dec = org.apachemons.codec.binary.Base64.decodeBase64(ciphertext);
try {
System.out.println("Private Key file name----"+PRIVATE_KEY_FILE);
privateKey = readPrivateKeyFromFile(PRIVATE_KEY_FILE);
} catch (IOException e) {
e.printStackTrace();
}
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decrypted = cipher.doFinal(dec);
return new String(decrypted, PLAIN_TEXT_ENCODING);
}
//reading private key from file
public PrivateKey readPrivateKeyFromFile(String fileName)
throws IOException {
FileInputStream fis = null;
ObjectInputStream ois = null;
try {
fis = new FileInputStream(new File(fileName));
ois = new ObjectInputStream(fis);
System.out.println("Private Key file-"+fileName);
BigInteger modulus = (BigInteger) ois.readObject();
BigInteger exponent = (BigInteger) ois.readObject();
// Get Private Key
RSAPrivateKeySpec rsaPrivateKeySpec = new RSAPrivateKeySpec(modulus, exponent);
KeyFactory fact = KeyFactory.getInstance("RSA");
PrivateKey privateKey = fact.generatePrivate(rsaPrivateKeySpec);
return privateKey;
} catch (Exception e) {
e.printStackTrace();
} finally {
if (ois != null) {
ois.close();
if (fis != null) {
fis.close();
}
}
}
return null;
}
Spent almost 2 days with different binations.I am generating a asymmetric key pair (public and private) in java using RSA algorithm and trying to use the public key in javascript to encrypt some text and decrypt back in java on server side. I am getting "javax.crypto.IllegalBlockSizeException: Data must not be longer than 128 bytes" exception while trying to decrypt back the string encrypted in javascript. Would appreciate some help...
Using thi Javascript library to encrypt.
https://github./wwwtyro/cryptico
var publicKeyString = ""// base64encoded public key string generated in java
Here is my javascript code
var EncryptionResult = cryptico.encrypt("somestring", publicKeyString);
console.log("Encrypted status-"+EncryptionResult.status);
console.log("Encrypted String-"+EncryptionResult.cipher);
It is successfully encrypting the string.
Java Key Generation and Decryption
Cipher cipher = Cipher.getInstance("RSA");
KeyFactory fact = KeyFactory.getInstance("RSA");
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(1024); // 1024 used for normal
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
FileOutputStream fos = null;
ObjectOutputStream oos = null;
Code to store the private key in file which is used to decrypt in decrypt method.
RSAPrivateKeySpec rsaPrivKeySpec = fact.getKeySpec(privateKey,
RSAPrivateKeySpec.class);
System.out.println("Writing private key...");
fos = new FileOutputStream(PRIVATE_KEY_FILE);
oos = new ObjectOutputStream(new BufferedOutputStream(fos));
oos = new ObjectOutputStream(new BufferedOutputStream(fos));
oos.writeObject(rsaPrivKeySpec.getModulus());
oos.writeObject(rsaPrivKeySpec.getPrivateExponent());
oos.close();
Decrypt method
public String decrypt(String ciphertext)
throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException
{
if (ciphertext.length() == 0) return null;
byte[] dec = org.apache.mons.codec.binary.Base64.decodeBase64(ciphertext);
try {
System.out.println("Private Key file name----"+PRIVATE_KEY_FILE);
privateKey = readPrivateKeyFromFile(PRIVATE_KEY_FILE);
} catch (IOException e) {
e.printStackTrace();
}
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decrypted = cipher.doFinal(dec);
return new String(decrypted, PLAIN_TEXT_ENCODING);
}
//reading private key from file
public PrivateKey readPrivateKeyFromFile(String fileName)
throws IOException {
FileInputStream fis = null;
ObjectInputStream ois = null;
try {
fis = new FileInputStream(new File(fileName));
ois = new ObjectInputStream(fis);
System.out.println("Private Key file-"+fileName);
BigInteger modulus = (BigInteger) ois.readObject();
BigInteger exponent = (BigInteger) ois.readObject();
// Get Private Key
RSAPrivateKeySpec rsaPrivateKeySpec = new RSAPrivateKeySpec(modulus, exponent);
KeyFactory fact = KeyFactory.getInstance("RSA");
PrivateKey privateKey = fact.generatePrivate(rsaPrivateKeySpec);
return privateKey;
} catch (Exception e) {
e.printStackTrace();
} finally {
if (ois != null) {
ois.close();
if (fis != null) {
fis.close();
}
}
}
return null;
}
Share
Improve this question
edited May 23, 2014 at 0:07
mawburn
2,3464 gold badges30 silver badges48 bronze badges
asked May 22, 2014 at 23:42
user2498258user2498258
1532 gold badges3 silver badges11 bronze badges
2
- 1 What's wrong with HTTPS/SSL? – spender Commented May 22, 2014 at 23:44
- Read this first to make sure you're actually protecting your users: "Javascript Cryptography Considered Harmful" matasano./articles/javascript-cryptography – dnault Commented May 23, 2014 at 0:06
3 Answers
Reset to default 2From the Cryptico
documentation it seems that it is not a simple RSA encryption, but a plex operation that generates AES key, encrypts it with RSA, encrypts the data with AES and outputs a concatenation of encrypted AES key and encrypted data. If you want to decrypt that in Java you will have to check the Cryptico
source code and reimplement the same in Java.
As for your current attempt and javax.crypto.IllegalBlockSizeException: Data must not be longer than 128 bytes
error:
When you do not specify the full transformation the default JCE transformation for RSA is RSA/ECB/PKCS1Padding.
In this mode the RSA encrypts or decrypts a single block of data which the length is not greater than the size of the key (more specifically, if the input sequence of bytes is interpreted as a big integer, its value should be less that the modulus used by the RSA). You can find additional information in this and this questions.
With the key size of 1024 bits the maximum data size is 128 bytes, and that is exactly what the exception says because the output of Cryptico
is obviously not a single RSA block and its length is greater that expected by "plain" RSA. Trying to use some other cipher mode or padding mode in Java will not help in that situation either.
Thanks Oleg for the detailed information. I will definitely take a look into it.
For now I switched to jsencrypt and it seems to work fine.
https://github./travist/jsencrypt
EDIT
How you get the encoded public key for the js encrypt?
Here is the solution for data Encryption from JS and Decrypt on Java(server side). I have used Cryptico js library for encryption(http://wwwtyro.github.io/cryptico/).
First of all we have to generate the java Keystore file from your local system. Don't use other Keystore files such as online Keystore. For creating the java Keystore(JKS) you can use KeyStore Explorer tool.
Below is the config I have used, using KeyStore Explorer tool
- Keystore type - JKS
- RSA algorithm - Keysize 1024
- Version - version 3
- Signature algorithm - SHA256 with RSA
- Validity period - 99 years(based on your requirement)
- Name filed - Fill all the mandatory fields - remember the "alias" and "password" what you entered here.
Finally, save the file as .jks on your local system.
Step-1
we have to use this Keystore file on the java side and we send the public key to the frontend.
I have created the service class which is responsible to load Keystore from the keystore file path(string), Keypair and Decrypt. You have to provide the alias, password, keystore type.
public KeyPair getExistingKeyStoreKeyPair(String keystorePath){
KeyPair generateKeyPair = null
try {
File file = new File(keystorePath)
KeyStore keyStore = loadKeyStore(file, "password", "JKS")
generateKeyPair = getKeyPair(keyStore, "fin360", "password")
} catch (Exception ex){
println(ex)
}
return generateKeyPair
}
public KeyStore loadKeyStore(final File keystoreFile, final String password, final String keyStoreType) throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
if (null == keystoreFile) {
throw new IllegalArgumentException("Keystore url may not be null")
}
final URI keystoreUri = keystoreFile.toURI()
final URL keystoreUrl = keystoreUri.toURL()
final KeyStore keystore = KeyStore.getInstance(keyStoreType)
InputStream is = null
try {
is = keystoreUrl.openStream();
keystore.load(is, null == password ? null : password.toCharArray())
} finally {
if (null != is) {
is.close()
}
}
return keystore;
}
public KeyPair getKeyPair(final KeyStore keystore, final String alias, final String password) {
PublicKey publicKey
PrivateKey privateKey
Key key
KeyPair keyPair
try {
key = (PrivateKey) keystore.getKey(alias, password.toCharArray())
final Certificate cert = keystore.getCertificate(alias)
publicKey = cert.getPublicKey()
privateKey = key
keyPair = new KeyPair(publicKey, privateKey)
} catch (Exception ex){
println(ex)
}
return keyPair;
}
public decryptData(String data, String keystorePath) throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException{
try {
byte[] dectyptedText = new byte[1]
byte[] byteArray = new byte[256]
BigInteger passwordInt = new BigInteger(data, 16)
if (passwordInt.toByteArray().length > 256) {
for (int i=1; i<257; i++) {
byteArray[i-1] = passwordInt.toByteArray()[i]
}
} else {
byteArray = passwordInt.toByteArray();
}
KeyPair generateKeyPair = getExistingKeyStoreKeyPair(keystorePath)
PrivateKey privateKey = generateKeyPair.getPrivate()
Cipher cipher = Cipher.getInstance("RSA")
cipher.init(Cipher.DECRYPT_MODE, privateKey)
dectyptedText = cipher.doFinal(byteArray)
String txt2 = new String(dectyptedText)
return txt2
}
catch (Exception ex){
println(ex)
return null
}
}
decryptData() method will playing the main role here. When you send the value data.getBytes() directly to the dycrypt method cipher.doFinal(byteArray)
you get the exception - IllegalBlockSizeException size should not more than 128 bytes. So we have get rid of the issue I get the workaroud here - [Getting 1 byte extra in the modulus RSA Key and sometimes for exponents also
Basically it adds the zero when we converting data from BigInteger to byteArray. So I removed the zero from the array.
Let's start use the service class to get the key values.
String publicKey= null
String keystorePath = your file path
KeyPair generateKeyPair = encryptDecryptService.getExistingKeyStoreKeyPair(keystorePath)
PublicKey publicKey1 = generateKeyPair.getPublic()
KeyFactory keyFactory;
RSAPublicKeySpec rsaPublicKeySpec = new RSAPublicKeySpec(BigInteger.ZERO, BigInteger.ZERO)
try {
keyFactory = KeyFactory.getInstance("RSA")
rsaPublicKeySpec = keyFactory.getKeySpec(publicKey1, RSAPublicKeySpec.class)
} catch(NoSuchAlgorithmException e1) {
println(e1)
} catch(InvalidKeySpecException e) {
println(e)
}
String testPublicKey = rsaPublicKeySpec.getModulus().toString(16)
publicKey = testPublicKey
Send you publicKey to JS. In your HTML or servlet import all the required js and jar files(you will get it from the cryptico js library).
try{
var rsa = new RSAKey();
rsa.setPublic(pub, "10001");
password = rsa.encrypt(password);
formdata = "password="+password+"&dataEncrypt=true";
}
catch (error){
console.log(error);
}
above I have directly used new RSA()
instance(in cryptico library it will be different. Internaly library is using the same) and set the publickey to the instance. We have to use hex string value is '10001'. Form the query string with encrypted data which we send to server. Form data holds the encrypted data well as well as 'dataEncrypt' key value. I used to check whether data is encrypted or not.
Finally on the server side you will get the request params and below is the code for decrypt.
Boolean isDataEncrypted = false
String decryptedPassword = null
isDataEncrypted = params.containsKey("dataEncrypt")
if(params.containsKey("password")){
if(isDataEncrypted) {
String keystorePath = helperService.fetchKeystoreFilePath()
decryptedPassword = encryptDecryptService.decryptData(params.password, keystorePath)
// update decrypted data into request params
params.password = decryptedPassword
}
}
println("Data decrypted => " + decryptedPassword)
本文标签: RSA Encryption Javascript and Decrypt JavaStack Overflow
版权声明:本文标题:RSA Encryption Javascript and Decrypt Java - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741877608a2402557.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论