基于PKCS#1 V2.1规范的OAEPWithSHA-512AndMGF1Padding算法实现
java中可以直接使用RSA/ECB/OAEPWithSHA-512AndMGF1Padding来完成公钥加密数据。
例如:
public static byte[] encode(byte[] data) throws Exception
{
byte[] keyBytes = Base64Utils.getFromBASE64(key);
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
Key publicKey = keyFactory.generatePublic(x509KeySpec);
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-512AndMGF1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(data);
}
其他语言与java语言对接时,可以参考如下填充算法实现过程:
package com.matrix.cipher;
public abstract class Base64Utils
{
public static String encode(byte[] btData)
{
int iLen = 0;
boolean l_bFlag;
int l_iGroup;
char[] l_szData;
byte[] l_btTmp;
int ii;
int jj;
int kk;
String l_stEncoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
if (btData == null)
{
return null;
}
if ((iLen <= 0) || (iLen > btData.length))
{
iLen = btData.length;
}
l_bFlag = ((iLen % 3) == 0);
l_iGroup = iLen / 3;
ii = l_iGroup;
if (!l_bFlag)
{
ii++;
}
l_szData = new char[4 * ii];
l_btTmp = new byte[3];
for (ii = 0, jj = 0, kk = 0; ii < l_iGroup; ii++)
{
l_btTmp[0] = btData[kk++];
l_btTmp[1] = btData[kk++];
l_btTmp[2] = btData[kk++];
l_szData[jj++] = l_stEncoding.charAt((l_btTmp[0] >> 2) & 0x3F);
l_szData[jj++] = l_stEncoding.charAt(((l_btTmp[0] & 0x03) << 4)
| ((l_btTmp[1] >> 4) & 0x0F));
l_szData[jj++] = l_stEncoding.charAt(((l_btTmp[1] & 0x0F) << 2)
| ((l_btTmp[2] >> 6) & 0x03));
l_szData[jj++] = l_stEncoding.charAt(l_btTmp[2] & 0x3F);
}
if (!l_bFlag)
{
l_btTmp[0] = btData[kk++];
l_szData[jj++] = l_stEncoding.charAt((l_btTmp[0] >> 2) & 0x3F);
l_szData[jj + 1] = '=';
l_szData[jj + 2] = '=';
if ((iLen % 3) == 1)
{
l_szData[jj] = l_stEncoding.charAt((l_btTmp[0] & 0x03) << 4);
}
else
// if ((iLen % 3) == 2)
{
l_btTmp[1] = btData[kk];
l_szData[jj++] = l_stEncoding.charAt(((l_btTmp[0] & 0x03) << 4)
| ((l_btTmp[1] >> 4) & 0x0F));
l_szData[jj] = l_stEncoding.charAt((l_btTmp[1] & 0x0F) << 2);
}
}
return new String(l_szData);
}
public static byte[] getFromBASE64(String stData)
{
if (null == stData || stData.trim().isEmpty())
{
return null;
}
int l_iLen;
int l_iGroup;
int ii;
int jj;
int kk;
boolean l_bFlag;
char[] l_szTmp;
byte[] l_btData = new byte[0];
l_iLen = stData.length();
if ((l_iLen % 4) != 0)
{
return l_btData;
}
l_iGroup = l_iLen / 4;
ii = l_iGroup * 3;
l_bFlag = true;
l_szTmp = new char[4];
if (stData.charAt(l_iLen - 1) == '=')
{
l_iLen--;
ii--;
l_iGroup--;
l_bFlag = false;
if (stData.charAt(l_iLen - 1) == '=')
{
l_iLen--;
ii--;
}
}
for (jj = 0; jj < l_iLen; jj++)
{
l_szTmp[0] = stData.charAt(jj);
if (!((l_szTmp[0] == '+')
|| (('/' <= l_szTmp[0]) && (l_szTmp[0] <= '9'))
|| (('A' <= l_szTmp[0]) && (l_szTmp[0] <= 'Z')) || (('a' <= l_szTmp[0]) && (l_szTmp[0] <= 'z'))))
{
return l_btData;
}
}
l_btData = new byte[ii];
for (ii = 0, jj = 0, kk = 0; ii < l_iGroup; ii++)
{
l_szTmp[0] = returnToData(stData.charAt(kk++));
l_szTmp[1] = returnToData(stData.charAt(kk++));
l_szTmp[2] = returnToData(stData.charAt(kk++));
l_szTmp[3] = returnToData(stData.charAt(kk++));
l_btData[jj++] = (byte) ((l_szTmp[0] << 2) | ((l_szTmp[1] >> 4) & 0x03));
l_btData[jj++] = (byte) ((l_szTmp[1] << 4) | ((l_szTmp[2] >> 2) & 0x0F));
l_btData[jj++] = (byte) ((l_szTmp[2] << 6) | (l_szTmp[3] & 0x3F));
}
if (!l_bFlag)
{
l_szTmp[0] = returnToData(stData.charAt(kk++));
l_szTmp[1] = returnToData(stData.charAt(kk++));
l_btData[jj++] = (byte) ((l_szTmp[0] << 2) | ((l_szTmp[1] >> 4) & 0x03));
if ((l_iLen % 4) == 3)
{
l_szTmp[2] = returnToData(stData.charAt(kk));
l_btData[jj] = (byte) ((l_szTmp[1] << 4) | ((l_szTmp[2] >> 2) & 0x0F));
}
}
return l_btData;
}
private static char returnToData(char cChar)
{
if (('A' <= cChar) && (cChar <= 'Z'))
{
cChar -= 'A';
}
else if (('a' <= cChar) && (cChar <= 'z'))
{
cChar -= 'a';
cChar += 26;
}
else if (('0' <= cChar) && (cChar <= '9'))
{
cChar -= '0';
cChar += 52;
}
else if (cChar == '+')
{
cChar = 62;
}
else
// if (cChar == '/')
{
cChar = 63;
}
return cChar;
}
}
package com.matrix.cipher;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class SHAUtils
{
/**
* @param strSrc
* @param encName
* :SHA-1;SHA-256;SHA-512;
* @return
*/
public static byte[] encrypt(String strSrc, String encName)
{
MessageDigest md = null;
byte[] encode = null;
try
{
byte[] bt = strSrc.getBytes("UTF-8");
md = MessageDigest.getInstance(encName);
md.update(bt);
encode = md.digest();
}
catch (NoSuchAlgorithmException e)
{
return null;
}
catch (UnsupportedEncodingException e)
{
return null;
}
return encode;
}
public static byte[] encryptSHA1(String strSrc)
{
return encrypt(strSrc, "SHA-1");
}
public static byte[] encryptSHA256(String strSrc)
{
return encrypt(strSrc, "SHA-256");
}
public static byte[] encryptSHA512(String strSrc)
{
return encrypt(strSrc, "SHA-512");
}
}
package com.matrix.cipher;
import java.security.MessageDigest;
/**
* 掩模生成函数
* mask generator function, as described in PKCS1v2.
*/
public class MGF1
{
private MessageDigest digest;
/**
* Create a version of MGF1 for the given digest.
*
* @param digest
* digest to use as the basis of the function.
*/
public MGF1(MessageDigest digest)
{
this.digest = digest;
}
/**
* int to octet string.
*/
private void I2OSP(int i, byte[] sp)
{
sp[0] = (byte) (i >>> 24);
sp[1] = (byte) (i >>> 16);
sp[2] = (byte) (i >>> 8);
sp[3] = (byte) (i >>> 0);
}
/**
* Generate the mask.
*
* @param seed
* source of input bytes for initial digest state
* @param length
* length of mask to generate
*
* @return a byte array containing a MGF1 generated mask
*/
public byte[] generateMask(byte[] seed, int length)
{
byte[] mask = new byte[length];
byte[] C = new byte[4];
int counter = 0;
int hLen = digest.getDigestLength();
digest.reset();
while (counter < (length / hLen))
{
I2OSP(counter, C);
digest.update(seed);
digest.update(C);
System.arraycopy(digest.digest(), 0, mask, counter * hLen, hLen);
counter++;
}
if ((counter * hLen) < length)
{
I2OSP(counter, C);
digest.update(seed);
digest.update(C);
System.arraycopy(digest.digest(), 0, mask, counter * hLen,
mask.length - (counter * hLen));
}
return mask;
}
}
package com.matrix.cipher;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
/**
* @author Matrix
*
*/
public class RSA2048Utils
{
public static final String ALGORITHM = "RSA";
private static String RSA_TRANSFORMATION = "RSA/ECB/NoPadding";
/**
* 首先要取得公钥,并使用setPublicKey方法来初始化变量key
*/
public static String key;
public static byte[] encode(byte[] data) throws Exception
{
byte[] keyBytes = Base64Utils.getFromBASE64(key);
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
RSAPublicKey publicKey = (RSAPublicKey) keyFactory
.generatePublic(x509KeySpec);
Cipher cipher = Cipher.getInstance(RSA_TRANSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] EM = OAEPWithSHA512AndMGF1Padding(data, publicKey);
return cipher.doFinal(EM);
}
private static byte[] OAEPWithSHA512AndMGF1Padding(byte[] data,
RSAPublicKey publicKey) throws Exception
{
byte[] lHash = SHAUtils.encrypt("", "SHA-512");
byte[] ps = new byte[publicKey.getModulus().bitLength() / 8
- data.length - 2 * lHash.length - 2];
for (int i = 0; i < ps.length; i++)
{
ps[i] = 0;
}
byte[] DB = new byte[publicKey.getModulus().bitLength() / 8
- lHash.length - 1];
System.arraycopy(lHash, 0, DB, 0, lHash.length);
System.arraycopy(ps, 0, DB, lHash.length, ps.length);
DB[lHash.length + ps.length] = 1;
System.arraycopy(data, 0, DB, lHash.length + ps.length + 1, data.length);
byte[] seed = SecureRandom.getSeed(lHash.length);
MGF1 mgf1 = new MGF1(MessageDigest.getInstance("SHA-1"));
byte[] dbMask = mgf1.generateMask(seed, publicKey.getModulus()
.bitLength() / 8 - lHash.length - 1);
// DB和dbMask做异或运算生成maskedDB
byte[] maskedDB = new BigInteger(DB).xor(new BigInteger(dbMask))
.toByteArray();
byte[] seedMask = mgf1.generateMask(maskedDB, lHash.length);
// seed和seedMask做异或运算生成maskedSeed
byte[] maskedSeed = new BigInteger(seed).xor(new BigInteger(seedMask))
.toByteArray();
byte[] EM = new byte[publicKey.getModulus().bitLength() / 8];
EM[0] = 0;
System.arraycopy(maskedSeed, 0, EM, 1, maskedSeed.length);
System.arraycopy(maskedDB, 0, EM, maskedSeed.length + 1,
maskedDB.length);
return EM;
}
/**
* @param key
*/
public static void setPublicKey(String key)
{
RSA2048Utils.key = key;
}
}