SM2非對稱加密算法工具類Java版

所需依賴
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15on</artifactId>
            <version>1.65</version>
            <optional>true</optional>
        </dependency>
曲線參數
/**
 * 國密辦SM2曲線推薦參數
 * @author zhangjian
 * @date 2020-11-06
 */
public class SM2Params {
    //P256V1Curve 代表國密SM2推薦參數定義的橢圓曲線:
    public static final SM2P256V1Curve CURVE = new SM2P256V1Curve();
    //橢圓基點G的階
    public static final BigInteger SM2_ECC_N = CURVE.getOrder();
    //橢圓曲線上所有點的個數與SM2_ECC_N相除的整數部分
    public static final BigInteger SM2_ECC_H = CURVE.getCofactor();
    //橢圓基點G x軸坐標
    public static final BigInteger SM2_ECC_GX = new BigInteger(
            "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", 16);
    //橢圓基點G y軸坐標
    public static final BigInteger SM2_ECC_GY = new BigInteger(
            "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", 16);
    //橢圓基點G
    public static final ECPoint G_POINT = CURVE.createPoint(SM2_ECC_GX, SM2_ECC_GY);
    //設置橢圓曲線參數
    public static final ECDomainParameters DOMAIN_PARAMS = new ECDomainParameters(CURVE, G_POINT,
            SM2_ECC_N, SM2_ECC_H);

}
加解密工具類
**
 * 國密SM4加解密
 *
 * @author zhangjian
 * @date 2020-11-05
 */
public class SM4Helper {

    static {
        //加入BouncyCastleProvider的支持 BouncyCastle->開源密碼包,擴充密碼算法支持
        Security.addProvider(new BouncyCastleProvider());
    }

    //算法名稱
    public static final String ALGORITHM_NAME = "SM4";

    //ECB P5填充
    public static final String ALGORITHM_NAME_ECB_PADDING = "SM4/ECB/PKCS5Padding";

    //CBC P5填充
    public static final String ALGORITHM_NAME_CBC_PADDING = "SM4/CBC/PKCS5Padding";

    //密鑰長度
    public static final int DEFAULT_KEY_SIZE = 128;

    private static final Log LOG = LogFactory.getLog(SM2Helper.class);

    /**
     * 獲取密鑰
     * @return 密鑰
     * @throws Exception 異常
     */

    public static byte[] generateKey() {
        try {
            return generateKey(DEFAULT_KEY_SIZE);
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
        }
        return null;
    }

    /**
     * 獲取指定長度密鑰
     * @param keySize 密鑰的長度
     * @return 密鑰
     * @throws Exception 異常
     */

    public static byte[] generateKey(int keySize) {
        try {
            KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM_NAME,
                    BouncyCastleProvider.PROVIDER_NAME);
            kg.init(keySize, new SecureRandom());
            return kg.generateKey().getEncoded();
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
        }
        return null;
    }

    /**
     * ECB P5填充加密
     * 優(yōu)點:簡單第步,利于并行計算,誤差不會被傳遞
     * 缺點:加密模式易被確定
     * @param key 密鑰
     * @param data 明文數據
     * @return 加密結果
     * @throws Exception 異常
     */
    public static String encryptEcbPadding(String key, String data) {
        try {
            Cipher cipher = generateEcbCipher(ALGORITHM_NAME_ECB_PADDING, Cipher.ENCRYPT_MODE,
                    BinaryUtils.parseHexString(key));
            byte[] encryptBytes = cipher.doFinal(data.getBytes("UTF-8"));
            return BinaryUtils.toHexStr(encryptBytes);
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
        }
        return null;
    }

    /**
     * ECB P5填充解密
     * @param key 密鑰
     * @param cipherText 加密后的數據
     * @return 解密結果
     */

    public static String decryptEcbPadding(String key, String cipherText) {
        try {
            Cipher cipher = generateEcbCipher(ALGORITHM_NAME_ECB_PADDING, Cipher.DECRYPT_MODE,
                    BinaryUtils.parseHexString(key));
            byte[] decryptBytes = cipher.doFinal(BinaryUtils.parseHexString(cipherText));
            return new String(decryptBytes);
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
        }
        return null;
    }

    /**
     * CBC P5填充加密
     * 優(yōu)點:安全性高
     * 缺點:不利于并行計算衷畦,誤差傳遞骂维,需要初始化向量iv
     * @param key 密鑰
     * @param iv 偏移量稀轨,CBC每輪迭代會和上輪結果進行異或操作填物,由于首輪沒有可進行異或的結果冰单,
     *           所以需要設置偏移量幌缝,一般用密鑰做偏移量
     * @param data 明文數據
     * @return 加密結果
     */

    public static String encryptCbcPadding(String key, String iv, String data) {
        try {
            Cipher cipher = generateCbcCipher(ALGORITHM_NAME_CBC_PADDING, Cipher.ENCRYPT_MODE,
                    BinaryUtils.parseHexString(key), BinaryUtils.parseHexString(iv));
            byte[] encryptBytes = cipher.doFinal(data.getBytes("UTF-8"));
            return BinaryUtils.toHexStr(encryptBytes);
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
        }
        return null;
    }

    /**
     * CBC P5填充解密
     * @param key 密鑰
     * @param iv 偏移量,CBC每輪迭代會和上輪結果進行異或操作诫欠,由于首輪沒有可進行異或的結果涵卵,
     *           所以需要設置偏移量浴栽,一般用密鑰做偏移量
     * @param cipherText 加密數據
     * @return 解密結果
     */
    public static String decryptCbcPadding(String key, String iv, String cipherText) {
        try {
            Cipher cipher = generateCbcCipher(ALGORITHM_NAME_CBC_PADDING, Cipher.DECRYPT_MODE,
                    BinaryUtils.parseHexString(key), BinaryUtils.parseHexString(iv));
            byte[] decryptBytes = cipher.doFinal(BinaryUtils.parseHexString(cipherText));
            return new String(decryptBytes);
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
        }
        return null;
    }

    /**
     * ECB P5填充加解密Cipher初始化
     * @param algorithmName 算法名稱
     * @param mode 1 加密  2解密
     * @param key 密鑰
     * @return Cipher
     */
    private static Cipher generateEcbCipher(String algorithmName, int mode, byte[] key) {
        try {
            Cipher cipher = Cipher.getInstance(algorithmName, BouncyCastleProvider.PROVIDER_NAME);
            Key sm4Key = new SecretKeySpec(key, ALGORITHM_NAME);
            cipher.init(mode, sm4Key);
            return cipher;
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
        }
        return null;
    }

    /**
     * CBC P5填充加解密Cipher初始化
     * @param algorithmName 算法名稱
     * @param mode 1 加密  2解密
     * @param key 密鑰
     * @param iv 偏移量,CBC每輪迭代會和上輪結果進行異或操作轿偎,由于首輪沒有可進行異或的結果典鸡,
     *           所以需要設置偏移量,一般用密鑰做偏移量
     * @return Cipher
     */
    private static Cipher generateCbcCipher(String algorithmName, int mode, byte[] key, byte[] iv) {
        try {
            Cipher cipher = Cipher.getInstance(algorithmName, BouncyCastleProvider.PROVIDER_NAME);
            Key sm4Key = new SecretKeySpec(key, ALGORITHM_NAME);
            IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
            cipher.init(mode, sm4Key, ivParameterSpec);
            return cipher;
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
        }
        return null;
    }
}
單元測試
    @Test
    public void testEncryptAndDecryptContent(){
        String publicKey = getPublicKeyParameters();
        String privateKey = getPrivateKeyParameters();

        String data = "123456";
        //C1C2C3 mode
        String encrypt = encrypt(data, publicKey);
        System.out.println("加密結果:" + encrypt);
        String decrypt = SM2Helper.decrypt(encrypt, privateKey);
        System.out.println("解密數據" + decrypt);
        Assert.assertEquals(data, decrypt);
    }
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末贴硫,一起剝皮案震驚了整個濱河市椿每,隨后出現的幾起案子,更是在濱河造成了極大的恐慌英遭,老刑警劉巖,帶你破解...
    沈念sama閱讀 223,002評論 6 519
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件亦渗,死亡現場離奇詭異挖诸,居然都是意外死亡,警方通過查閱死者的電腦和手機法精,發(fā)現死者居然都...
    沈念sama閱讀 95,357評論 3 400
  • 文/潘曉璐 我一進店門多律,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人搂蜓,你說我怎么就攤上這事狼荞。” “怎么了帮碰?”我有些...
    開封第一講書人閱讀 169,787評論 0 365
  • 文/不壞的土叔 我叫張陵相味,是天一觀的道長。 經常有香客問我殉挽,道長丰涉,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,237評論 1 300
  • 正文 為了忘掉前任斯碌,我火速辦了婚禮一死,結果婚禮上,老公的妹妹穿的比我還像新娘傻唾。我一直安慰自己投慈,他們只是感情好,可當我...
    茶點故事閱讀 69,237評論 6 398
  • 文/花漫 我一把揭開白布冠骄。 她就那樣靜靜地躺著伪煤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪猴抹。 梳的紋絲不亂的頭發(fā)上带族,一...
    開封第一講書人閱讀 52,821評論 1 314
  • 那天,我揣著相機與錄音蟀给,去河邊找鬼蝙砌。 笑死阳堕,一個胖子當著我的面吹牛,可吹牛的內容都是我干的择克。 我是一名探鬼主播恬总,決...
    沈念sama閱讀 41,236評論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼肚邢!你這毒婦竟也來了壹堰?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 40,196評論 0 277
  • 序言:老撾萬榮一對情侶失蹤骡湖,失蹤者是張志新(化名)和其女友劉穎贱纠,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體响蕴,經...
    沈念sama閱讀 46,716評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡谆焊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,794評論 3 343
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了浦夷。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片辖试。...
    茶點故事閱讀 40,928評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖劈狐,靈堂內的尸體忽然破棺而出罐孝,到底是詐尸還是另有隱情,我是刑警寧澤肥缔,帶...
    沈念sama閱讀 36,583評論 5 351
  • 正文 年R本政府宣布莲兢,位于F島的核電站,受9級特大地震影響辫继,放射性物質發(fā)生泄漏怒见。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,264評論 3 336
  • 文/蒙蒙 一姑宽、第九天 我趴在偏房一處隱蔽的房頂上張望遣耍。 院中可真熱鬧,春花似錦炮车、人聲如沸舵变。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,755評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽纪隙。三九已至,卻和暖如春扛或,著一層夾襖步出監(jiān)牢的瞬間拼卵,已是汗流浹背术浪。 一陣腳步聲響...
    開封第一講書人閱讀 33,869評論 1 274
  • 我被黑心中介騙來泰國打工睡腿, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留熊杨,地道東北人莺丑。 一個月前我還...
    沈念sama閱讀 49,378評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子钠绍,可洞房花燭夜當晚...
    茶點故事閱讀 45,937評論 2 361

推薦閱讀更多精彩內容