/*
* Copyright Beijing 58 Information Technology Co.,Ltd.
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.bj58.spat.gaea.secure;
import java.io.UnsupportedEncodingException;
import java.security.Key;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
/**
* DESCoderHelper
*
* @author Service Platform Architecture Team (spat@58.com)
*/
public class DESCoderHelper {
public static final String KEY_ALGORITHM = "DES";
public static final String CIPHER_ALGORITHM_ECB = "DES/ECB/PKCS5Padding";
public static final String CIPHER_ALGORITHM_CBC = "DES/CBC/PKCS5Padding";
public static final String CHAR_ENCODING = "utf-8";
public static DESCoderHelper getInstance(){
return new DESCoderHelper();
}
/**
* 转换密钥
* @param key byte类型密钥
* @return key 密钥
* @throws Exception
*/
private Key toKey(byte[] key)throws Exception{
DESKeySpec dks = new DESKeySpec(key);
SecretKeyFactory skf = SecretKeyFactory.getInstance(KEY_ALGORITHM);
//生成密钥
SecretKey secretKey = skf.generateSecret(dks);
return secretKey;
}
/**
* 生成8位byte密钥(系统自动生成)
* java默认密钥长度为56位
* @return byte[] 8位byte
* @throws Exception
*/
private byte[] initkey()throws Exception{
KeyGenerator kg = KeyGenerator.getInstance(KEY_ALGORITHM);
kg.init(56);
SecretKey secretKey = kg.generateKey();
return secretKey.getEncoded();
}
/**
* 生成密钥(系统自动生成)
* 用于java环境,c#下不可使用
* @return String
* @throws Exception
*/
public String initkeyString()throws Exception{
return Base64.encodeBase64String(initkey());
}
/**
* 生成密钥(系统自动生成)
* 用于java环境,c#下不可使用
* @return String
* @throws Exception
*/
public String initkeyString(String key)throws Exception{
return Base64.encodeBase64String(initkey(key));
}
/**
* 生成密钥(自定义)
* 用于java环境c#下不可使用
* 使用 key 中的前 8 个字节作为 DES 密钥的密钥内容
* @return
* @throws Exception
*/
public byte[] initkey(String key)throws Exception{
if(key == null || key.getBytes().length < 8) {
throw new Exception("key不合法, 长度必须大于8个字节!");
}
byte[] bufKey = key.getBytes(CHAR_ENCODING);
DESKeySpec dks = new DESKeySpec(bufKey);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
SecretKey securekey = keyFactory.generateSecret(dks);
return securekey.getEncoded();
}
/**
* 加密
* @param data 原文byte类型
* @param key 密钥byte类型
* @return byte[] 密文byte类型
* @throws Exception
*/
public byte[] encrypt(byte[] data,byte[] key) throws Exception{
Key k = toKey(key);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM_ECB);
cipher.init(cipher.ENCRYPT_MODE, k);
return cipher.doFinal(data);
}
/**
* 加密
* @param data 原文byte类型
* @param key 密钥byte类型
* @return String 密文
* @throws Exception
*/
public String encryptString(byte[] data,byte[] key) throws Exception{
return Base64.encodeBase64String(encrypt(data,key));
}
/**
* 加密
* @param data 原文
* @param key 密钥
* @return 密文
* @throws Exception
*/
public String encryptString(String data,String key) throws Exception{
return encryptString(data.getBytes(CHAR_ENCODING),key.getBytes(CHAR_ENCODING));
}
/**
* 解密
* @param data 密文byte类型
* @param key 密钥
* @return byte[] 原文byte类型
* @throws Exception
*/
public byte[] decrypt(byte[] data,byte[] key) throws Exception{
Key k = toKey(key);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM_ECB);
cipher.init(cipher.DECRYPT_MODE, k);
return cipher.doFinal(data);
}
/**
* 解密
* data数据为base64加密后的字符串
* @param data 密文
* @param key 密钥
* @return 原文
* @throws Exception
*/
private String decrypt(String data,String key) throws Exception{
return new String(decrypt(Base64.decodeBase64(data), key.getBytes(CHAR_ENCODING)));
}
/**
* 加密
* 该方法与c#互通
* @param data 原文
* @param key 密钥(IV length must be 8 bytes long)
* @return byte 密文byte类型
* @throws Exception
*/
public byte[] encryptNetByte(String data, String key) throws Exception {
keyLength(key);
return encryptNet(data.getBytes(CHAR_ENCODING),key.getBytes(CHAR_ENCODING));
}
/**
* 加密
* 该方法与c#互通 内容
* @param data 原文
* @param key 密钥
* @return String 密文(密文为base64加密后的字符串)
* @throws Exception
*/
public String encryptNetString(String data, String key) throws Exception {
keyLength(key);
return Base64.encodeBase64String(encryptNetByte(data,key));
}
/**
* 加密
* 该方法与c#互通
* @param data 原文byte类型
* @param key 密钥 byte类型
* @return byte 密文byte类型(IV length must be 8 bytes long)
* @throws Exception
*/
private byte[] encryptNet(byte[] data, byte[] key) throws Exception {
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM_CBC);
DESKeySpec desKeySpec = new DESKeySpec(key);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
IvParameterSpec iv = new IvParameterSpec(key);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
return cipher.doFinal(data);
}
/**
* 解密
* 该方法与c#互通
* 如果密文为base64加密后的字符串,则需要base64解密为byte进行解码,
* 否则会抛出 BadPaddingException: Given final block not properly padded 异常
* @param data 密文byte类型
* @param key 密钥byte类型(IV length must be 8 bytes long)
* @return 原文byte类型
* @throws Exception
*/
private byte[] decryptNet(byte[] data, byte[] key) throws Exception {
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM_CBC);
DESKeySpec desKeySpec = new DESKeySpec(key);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
IvParameterSpec iv = new IvParameterSpec(key);
cipher.init(Cipher.DECRYPT_MODE,secretKey, iv);
return cipher.doFinal(data);
}
/**
* 解密
* 该方法与c#互通
* data密文类型为base64加密后的字符串
* key为密钥,本方法通过UTF-8方式获得key的byte类型
* @param data 密文
* @param key 密钥(IV length must be 8 bytes long)
* @return 原文
* @throws Exception
*/
public String decryptNetString(String data, String key) throws Exception {
keyLength(key);
return new String(decryptNet(Base64.decodeBase64(data),key.getBytes(CHAR_ENCODING)));
}
/**
* 解密
* 该方法与c#互通
* data密文类型为原文加密后的byte类型,如果密文通过base64加密为字符串形式,解码请用方法decryptNetString(String data,String key)
* 如通过通过base64加密后字符串getByte方式调用该方法会抛出BadPaddingException: Given final block not properly padded 异常
* key为密钥byte类型,为防止乱码问题建议使用时通过getByte("UTF-8")获取byte类型
* @param data 密文byte类型
* @param key 密钥byte类型(IV length must be 8 bytes long)
* @return 原文
* @throws Exception
*/
public String decryptNetString(byte[] data, byte[] key) throws Exception {
keyLength(key);
return new String(decryptNet(data,key));
}
/**
* 判断key length
* @param key
* @throws Exception
* @throws UnsupportedEncodingException
*/
private void keyLength(String key) throws Exception{
keyLength(key.getBytes(CHAR_ENCODING));
}
private void keyLength(byte[] key) throws Exception{
if(key.length != 8){
throw new Exception("key length must be 8 bytes long!");
}
}
/**main 测试
* @throws Exception */
public static void main(String []args) throws Exception{
DESCoderHelper descode = DESCoderHelper.getInstance();
String key = descode.initkeyString();//cHZkc3V5dWg= cHZkc3V5dWg=
System.out.println("密钥:"+key);
System.out.println(descode.encryptNetString("58同城一个神奇的网站 very good! oh haha $&**&", "tsyg=af$"));
//System.out.println(decryptNetString("ZHg25iEgaOarDRbIfHNnXqPuMaOXPRo6CBTLUW2s8BOecSdJIoFQeI/g07ViN+KkxpJdW/ewNCQ=", key));
}
}