如何用java实现128位密钥的RSA算法

Python015

如何用java实现128位密钥的RSA算法,第1张

 import javax.crypto.Cipher

 import sun.misc.BASE64Decoder

 import sun.misc.BASE64Encoder

 import java.io.FileInputStream

 import java.io.FileOutputStream

 import java.io.ObjectInputStream

 import java.io.ObjectOutputStream

 import java.security.Key

 import java.security.KeyPair

 import java.security.KeyPairGenerator

import java.security.SecureRandom

 public class RSA_Encrypt {

 /** 指定加密算法为DESede */

 private static String ALGORITHM = "RSA"

 /** 指定key的大小 */

 private static int KEYSIZE = 128

 /** 指定公钥存放文件 */

 private static String PUBLIC_KEY_FILE = "PublicKey"

 /** 指定私钥存放文件 */

 private static String PRIVATE_KEY_FILE = "PrivateKey"

// private static String PUBLIC_KEY_FILE = "D://PublicKey.a"

// private static String PRIVATE_KEY_FILE = "D://PrivateKey.a"

 

 

 /**

 * 生成密钥

 */

 private static void generateKeyPair() throws Exception{

   /** RSA算法要求有一个可信任的随机数源 */

    SecureRandom sr = new SecureRandom()

    /** 为RSA算法创建一个KeyPairGenerator对象 */

    KeyPairGenerator kpg = KeyPairGenerator.getInstance(ALGORITHM)

   /** 利用上面的随机数据源初始化这个KeyPairGenerator对象 */

    kpg.initialize(KEYSIZE, sr)

    /** 生成密匙对 */

    KeyPair kp = kpg.generateKeyPair()

    /** 得到公钥 */

    Key publicKey = kp.getPublic()

    /** 得到私钥 */

    Key privateKey = kp.getPrivate()

    /** 用对象流将生成的密钥写入文件 */

    ObjectOutputStream oos1 = new ObjectOutputStream(new FileOutputStream(PUBLIC_KEY_FILE))

    ObjectOutputStream oos2 = new ObjectOutputStream(new FileOutputStream(PRIVATE_KEY_FILE))

    oos1.writeObject(publicKey)

    oos2.writeObject(privateKey)

    /** 清空缓存,关闭文件输出流 */

    oos1.close()

    oos2.close()

 }

 /**

 * 加密方法

 * source: 源数据

 */

 public static String encrypt(String source) throws Exception{

    generateKeyPair()

    /** 将文件中的公钥对象读出 */

    ObjectInputStream ois = new ObjectInputStream(new FileInputStream(PUBLIC_KEY_FILE))

    Key key = (Key) ois.readObject()

    ois.close()

    /** 得到Cipher对象来实现对源数据的RSA加密 */

    Cipher cipher = Cipher.getInstance(ALGORITHM)

    cipher.init(Cipher.ENCRYPT_MODE, key)

    byte[] b = source.getBytes()

    /** 执行加密操作 */

    byte[] b1 = cipher.doFinal(b)

    BASE64Encoder encoder = new BASE64Encoder()

    return encoder.encode(b1)

 }

 /**

 * 解密算法

 * cryptograph:密文

 */

 public static String decrypt(String cryptograph) throws Exception{

    /** 将文件中的私钥对象读出 */

    ObjectInputStream ois = new ObjectInputStream(new FileInputStream(PRIVATE_KEY_FILE))

    Key key = (Key) ois.readObject()

    /** 得到Cipher对象对已用公钥加密的数据进行RSA解密 */

    Cipher cipher = Cipher.getInstance(ALGORITHM)

    cipher.init(Cipher.DECRYPT_MODE, key)

    BASE64Decoder decoder = new BASE64Decoder()

    byte[] b1 = decoder.decodeBuffer(cryptograph)

    /** 执行解密操作 */

    byte[] b = cipher.doFinal(b1)

    return new String(b)

 }

  

 public static void main(String[] args) {

  try {

   String source = "Hello World!"//要加密的字符串

   String cryptograph = encrypt(source)

   System.out.println(cryptograph)

   

   String target = decrypt(cryptograph)//解密密文

   System.out.println(target)

  } catch (Exception e) {

   // TODO Auto-generated catch block

   e.printStackTrace()

  }//生成的密文

 }

}

RSA的Java实现不能一次加密很大的字符,自己处理了一下,见下面的代码。Base64编码类用的是一个Public domain Base64 for java http://iharder.sourceforge.net/current/java/base64/其他的保存公钥到文件等简单的实现,就不详细说了,看代码吧。==============================================import java.security.*import java.security.spec.PKCS8EncodedKeySpecimport java.security.spec.X509EncodedKeySpecimport java.util.HashMapimport java.util.Mapimport javax.crypto.*import java.io.*public class Encryptor {private static final String KEY_FILENAME = "c:\\mykey.dat"private static final String OTHERS_KEY_FILENAME = "c:\\Otherskey.dat"// private static final int KEY_SIZE = 1024// private static final int BLOCK_SIZE = 117// private static final int OUTPUT_BLOCK_SIZE = 128private static final int KEY_SIZE = 2048//RSA key 是多少位的private static final int BLOCK_SIZE = 245 //一次RSA加密操作所允许的最大长度//这个值与 KEY_SIZE 已经padding方法有关。因为 1024的key的输出是128,2048key输出是256字节//可能11个字节用于保存padding信息了,所以最多可用的就只有245字节了。private static final int OUTPUT_BLOCK_SIZE = 256private SecureRandom secrandprivate Cipher rsaCipherprivate KeyPair keysprivate Map<String, Key>allUserKeyspublic Encryptor() throws Exception {try {allUserKeys = new HashMap<String, Key>()secrand = new SecureRandom()//SunJCE Provider 中只支持ECB mode,试了一下只有PKCS1PADDING可以直接还原原始数据,//NOPadding导致解压出来的都是blocksize长度的数据,还要自己处理//参见 http://java.sun.com/javase/6/docs/technotes/guides/security/SunProviders.html#SunJCEProvider////另外根据 Open-JDK-6.b17-src( http://www.docjar.com/html/api/com/sun/crypto/provider/RSACipher.java.html)// 中代码的注释,使用RSA来加密大量数据不是一种标准的用法。所以现有实现一次doFinal调用之进行一个RSA操作,//如果用doFinal来加密超过的一个操作所允许的长度数据将抛出异常。//根据keysize的长度,典型的1024个长度的key和PKCS1PADDING一起使用时//一次doFinal调用只能加密117个byte的数据。(NOPadding 和1024 keysize时128个字节长度)//(2048长度的key和PKCS1PADDING 最多允许245字节一次)//想用来加密大量数据的只能自己用其他办法实现了。可能RSA加密速度比较慢吧,要用AES才行rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING")} catch (NoSuchAlgorithmException e) {e.printStackTrace()} catch (NoSuchPaddingException e) {e.printStackTrace()throw e}ObjectInputStream intry {in = new ObjectInputStream(new FileInputStream(KEY_FILENAME))} catch (FileNotFoundException e) {if (false == GenerateKeys()){throw e}LoadKeys()return}keys = (KeyPair) in.readObject()in.close()LoadKeys()}/** 生成自己的公钥和私钥*/private Boolean GenerateKeys() {try {KeyPairGenerator keygen = KeyPairGenerator.getInstance("RSA")// secrand = new SecureRandom()// sedSeed之后会造成 生成的密钥都是一样的// secrand.setSeed("chatencrptor".getBytes())// 初始化随机产生器//key长度至少512长度,不过好像说现在用2048才算比较安全的了keygen.initialize(KEY_SIZE, secrand)// 初始化密钥生成器keys = keygen.generateKeyPair()// 生成密钥组AddKey("me", EncodeKey(keys.getPublic()))} catch (NoSuchAlgorithmException e) {e.printStackTrace()return false}ObjectOutputStream outtry {out = new ObjectOutputStream(new FileOutputStream(KEY_FILENAME))} catch (IOException e) {e.printStackTrace()return false}try {out.writeObject(keys)} catch (IOException e) {e.printStackTrace()return false} finally {try {out.close()} catch (IOException e) {e.printStackTrace()return false}}return true}public String EncryptMessage(String toUser, String Message) throws IOException {Key pubkey = allUserKeys.get(toUser)if ( pubkey == null ){throw new IOException("NoKeyForThisUser") }try {//PublicKey pubkey = keys.getPublic()rsaCipher.init(Cipher.ENCRYPT_MODE, pubkey, secrand)//System.out.println(rsaCipher.getBlockSize())返回0,非block 加密算法来的?//System.out.println(Message.getBytes("utf-8").length)//byte[] encryptedData = rsaCipher.doFinal(Message.getBytes("utf-8"))byte[] data = Message.getBytes("utf-8")int blocks = data.length / BLOCK_SIZE int lastBlockSize = data.length % BLOCK_SIZE byte [] encryptedData = new byte[ (lastBlockSize == 0 ? blocks : blocks + 1)* OUTPUT_BLOCK_SIZE]for (int i=0i <blocksi++){//int thisBlockSize = ( i + 1 ) * BLOCK_SIZE >data.length ? data.length - i * BLOCK_SIZE : BLOCK_SIZE rsaCipher.doFinal(data,i * BLOCK_SIZE, BLOCK_SIZE, encryptedData ,i * OUTPUT_BLOCK_SIZE)}if (lastBlockSize != 0 ){rsaCipher.doFinal(data, blocks * BLOCK_SIZE, lastBlockSize,encryptedData ,blocks * OUTPUT_BLOCK_SIZE)}//System.out.println(encrypted.length)如果要机密的数据不足128/256字节,加密后补全成为变为256长度的。//数量比较小时,Base64.GZIP产生的长度更长,没什么优势//System.out.println(Base64.encodeBytes(encrypted,Base64.GZIP).length())//System.out.println(Base64.encodeBytes(encrypted).length())//System.out.println (rsaCipher.getOutputSize(30))//这个getOutputSize 只对 输入小于最大的block时才能得到正确的结果。其实就是补全 数据为128/256 字节return Base64.encodeBytes(encryptedData)} catch (InvalidKeyException e) {e.printStackTrace()throw new IOException("InvalidKey") }catch (ShortBufferException e) {e.printStackTrace()throw new IOException("ShortBuffer") }catch (UnsupportedEncodingException e) {e.printStackTrace()throw new IOException("UnsupportedEncoding") } catch (IllegalBlockSizeException e) {e.printStackTrace()throw new IOException("IllegalBlockSize") } catch (BadPaddingException e) {e.printStackTrace()throw new IOException("BadPadding") }finally {//catch 中 return 或者throw之前都会先调用一下这里}}public String DecryptMessage(String Message) throws IOException {byte[] decoded = Base64.decode(Message)PrivateKey prikey = keys.getPrivate()try {rsaCipher.init(Cipher.DECRYPT_MODE, prikey, secrand)int blocks = decoded.length / OUTPUT_BLOCK_SIZEByteArrayOutputStream decodedStream = new ByteArrayOutputStream(decoded.length)for (int i =0 i <blocks i ++ ){decodedStream.write (rsaCipher.doFinal(decoded,i * OUTPUT_BLOCK_SIZE, OUTPUT_BLOCK_SIZE))}return new String(decodedStream.toByteArray(), "UTF-8")} catch (InvalidKeyException e) {e.printStackTrace()throw new IOException("InvalidKey")} catch (UnsupportedEncodingException e) {e.printStackTrace()throw new IOException("UnsupportedEncoding")} catch (IllegalBlockSizeException e) {e.printStackTrace()throw new IOException("IllegalBlockSize")} catch (BadPaddingException e) {e.printStackTrace()throw new IOException("BadPadding")} finally {// catch 中 return 或者throw之前都会先调用一下这里。}}public boolean AddKey(String user, String key) {PublicKey publickeytry {publickey = DecodePublicKey(key)} catch (Exception e) {return false}allUserKeys.put(user, publickey)SaveKeys()return true}private boolean LoadKeys() {BufferedReader inputtry {input = new BufferedReader(new InputStreamReader(new FileInputStream(OTHERS_KEY_FILENAME)))} catch (FileNotFoundException e1) {// e1.printStackTrace()return false}

参考下面代码:

try {

    KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA",

            new org.bouncycastle.jce.provider.BouncyCastleProvider())

    final int KEY_SIZE = 128// 没什么好说的了,这个值关系到块加密的大小,可以更改,但是不要太大,否则效率会低

    keyPairGen.initialize(KEY_SIZE, new SecureRandom())

    KeyPair keyPair = keyPairGen.generateKeyPair()

    return keyPair

} catch (Exception e) {

    throw new Exception(e.getMessage())

}