I am now on making RSA message authentication software. The process is as follows:
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();
}
*/
%>
Your signature string contains 256 characters, however this is hexadecimal and really represents 128 bytes.
Before you verify the signature, you must convert it back to a byte array. This is not achieved through someString.getBytes()
but rather via DatatypeConverter.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).