user1349407 user1349407 - 4 months ago 31
Java Question

RSA decryption error - IllegalBlockSizeException: Data must not be longer than 128 bytes

I am now on making RSA message authentication software. The process is as follows:


  1. Sign the message by using A's private key (1024 bit)

  2. Verify the message by using A's public key (1024 bit)



The #1 code (below) works fine and generates following result:


5554c9a9f6838b6cf40d9dbfbab3d90ea27aa6434ed095d289c13c2624617993ad99161ac265276d150510c176341d8ab8600d08b7353286d465e6bd3370a6fd8dd3ffb82916f612fd6dcee5e654ed801cfca6b6d2d5d6dc99ff7921b615abdf62eb67db1f71e6a6ea70012fd35e7cefa1a8d3aab7614c47746cfe1fc2bc875b


However the #2 code shows following error:


javax.crypto.IllegalBlockSizeException: Data must not be longer than 128 bytes



I think the line in #1
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");

generates 2048 bits (256 bytes) result. Perhaps this is the problem... remember that I use 1024 bit private key.

So how can the #1 code generate 128-byte result?

1. SignMail.java

public class SignMail {

static {
Security.addProvider(new org.spongycastle.jce.provider.BouncyCastleProvider());
}

public static String sign(String userOriginalMessage) throws Exception {

PEMReader userPrivateKey = new PEMReader(
new InputStreamReader(
new FileInputStream(Environment.getExternalStorageDirectory()+"/pkcs10priv.key")));

KeyPair keyPair = (KeyPair)userPrivateKey.readObject();

byte[] cipherText;
//modified by JEON 20130817
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
//encrypt the message using private key
cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPrivate());
cipherText = cipher.doFinal(userOriginalMessage.getBytes());
return new String(Hex.encode(cipherText));

}


}


2. UserSMSVerifier.java

public class UserSMSVerifier {

static String signedMail;

static {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
}


public static String messageGenarator(
String UserCert,
String origninalMessage
) throws Exception{

InputStream userCertStream = new ByteArrayInputStream(UserCert.getBytes("UTF-8"));

PEMReader userCerti = new PEMReader(
new InputStreamReader(
userCertStream));



//KeyPair userPrivate = (KeyPair)userPrivateKey.readObject();
X509Certificate userCert = (X509Certificate)userCerti.readObject();


byte[] dectyptedText = null;
// decrypt the text using the private key
//modified by JEON 20130817
//Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, userCert.getPublicKey());
dectyptedText = cipher.doFinal(origninalMessage.getBytes());

String result = new String(dectyptedText, Charset.forName("UTF-8"));
return result;

}


}


the #2 code was executed by the following JSP

#3 messageVeri.JSP

<%@ page language="java" contentType="text/html; charset=euc-kr" %>

<%@ page session = "true" %>

<%@ page import="java.sql.DriverManager" %>
<%@ page import="java.sql.Connection" %>
<%@ page import="java.sql.PreparedStatement" %>
<%@ page import="java.sql.Statement" %>
<%@ page import="java.sql.SQLException" %>
<%@ page import="java.sql.ResultSet" %>

<%@ page import="myPackage.UserSMSVerifier" %>


<%
request.setCharacterEncoding("euc-kr");

String userID = request.getParameter("sender");
String encryptedSMS = request.getParameter("encryptedSMS");

//String sql = "select user_id, user_pw from testca.testca_init where user_id=? and user_pw=?";
//String sql = "update testca.testca_init set pkcs10request = '"+pkcs10request_new+"' where user_id='user1'";
String sql = "select * from testca.testca_init where user_id='" + userID + "'";

Class.forName("com.mysql.jdbc.Driver");

Connection conn = null;
PreparedStatement pstmt = null;

Statement stmt = null;
ResultSet rs = null;

String jdbcDriver = "jdbc:mysql://localhost:3306/";
String dbUser = "root";
String dbPass = "fo.......t";


try{
conn = DriverManager.getConnection(jdbcDriver, dbUser, dbPass);
stmt = conn.createStatement();
//stmt.executeUpdate(sql);
rs=stmt.executeQuery(sql);
while(rs.next()){
//rs=stmt.executeQuery(sql);
String userCertificate=rs.getString("certificate");
UserSMSVerifier.messageGenarator(userCertificate, encryptedSMS);
}



}catch(Exception ex){out.print("Error 2: " +ex);}
/*
if(rs.next())
{
//session.setAttribute("userID", userID);
out.print("Insert Succeed!");
out.println();
//out.print("Welcome!" + " " + session.getAttribute("userID"));
}
else
{
out.print("failed to login!");
//session.invalidate();
}
*/

%>

Answer

Your signature string contains 256 characters, however this is hexadecimal and really represents 128 bytes.

Before you verify the signature, you must convert this back to a byte array. This is not achieved through someString.getBytes() but rather via DatatypeConvert.parseHexBinary(someString) (or any other method you prefer from Google).

Also, I would strongly recommend you use the Signature class rather than the Cipher class when signing messages. Currently your code can only handle messages that are smaller than 128 bytes in length (smaller, in fact, due to padding). Instead, you should be hashing the message prior to signing (e.g. using the SHA256withRSA mechanism).

Comments