Android 数据SM4传输加解密

第一:场景介绍

  甲方要求,数据在传输过程中要加密。

第二:选择加解密方式:

这里面Android 和服务端都是选择SM4

第三:实现方式

1:服务端采用SpringBoot,在pom.xml 文件下添加依赖

		<dependency>
			<groupId>org.bouncycastle</groupId>
			<artifactId>bcprov-jdk15on</artifactId>
			<version>1.64</version>
		</dependency>

2:在Android 端同样添加依赖,在module 下面build.gradle

  implementation group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: '1.64'

3:服务端SM4工具类

package com.wansun.datahouse.visit.utils;

import org.apache.tomcat.util.buf.HexUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.Security;

/**
 * TODO:
 * 国密SM4算法
 *
 * @author Blade
 * @date 2022/5/9 17:13
 */
public class Sm4Util {

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

    /**
     * SM4算法ECB模式PKCS5Padding填充方式
     */
    public static final String ALGORITHM_NAME_ECB_PADDING = "SM4/ECB/PKCS5Padding";

    /**
     * SM4算法ECB模式不填充
     */
    public static final String ALGORITHM_NAME_ECB_NOPADDING = "SM4/ECB/NoPadding";

    /**
     * SM4算法CBC模式PKCS5Padding填充方式
     */
    public static final String ALGORITHM_NAME_CBC_PADDING = "SM4/CBC/PKCS5Padding";

    /**
     * SM4算法CBC模式不填充
     */
    public static final String ALGORITHM_NAME_CBC_NOPADDING = "SM4/CBC/NoPadding";

    /**
     * 默认key长度
     */
    public static final int DEFAULT_KEY_SIZE = 128;

    static {
        // 加入 BC 实现
        Security.addProvider(new BouncyCastleProvider());
    }

    /**
     * 生成秘钥 key
     *
     * @return key
     * @throws NoSuchAlgorithmException 异常
     * @throws NoSuchProviderException  异常
     */
    private static byte[] generateKey() throws NoSuchAlgorithmException, NoSuchProviderException {
        return generateKey(DEFAULT_KEY_SIZE);
    }

    /**
     * 生成秘钥 key
     *
     * @param keySize 秘钥长度
     * @return key
     * @throws NoSuchAlgorithmException 异常
     * @throws NoSuchProviderException  异常
     */
    private static byte[] generateKey(int keySize) throws NoSuchAlgorithmException, NoSuchProviderException {
        KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM_NAME, BouncyCastleProvider.PROVIDER_NAME);
        kg.init(keySize, new SecureRandom());
        return kg.generateKey().getEncoded();
    }

    /**
     * 生成ECB模式的cipher
     *
     * @param algorithmName 算法名称
     * @param mode          模式
     * @param key           秘钥
     * @return {@link Cipher} 密文
     * @throws NoSuchAlgorithmException 异常
     * @throws NoSuchProviderException  异常
     * @throws NoSuchPaddingException   异常
     * @throws InvalidKeyException      异常
     */
    private static Cipher generateEcbCipher(String algorithmName, int mode, byte[] key)
            throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException,
            InvalidKeyException {
        Cipher cipher = Cipher.getInstance(algorithmName, BouncyCastleProvider.PROVIDER_NAME);
        Key sm4Key = new SecretKeySpec(key, ALGORITHM_NAME);
        cipher.init(mode, sm4Key);
        return cipher;
    }

    /**
     * 用ECB模式和PKCS5Padding填充的方式 进行加密
     *
     * @param key  秘钥
     * @param data 加密前的数据
     * @return 加密后的数据
     * @throws InvalidKeyException       异常
     * @throws NoSuchAlgorithmException  异常
     * @throws NoSuchProviderException   异常
     * @throws NoSuchPaddingException    异常
     * @throws IllegalBlockSizeException 异常
     * @throws BadPaddingException       异常
     */
    private static byte[] encryptEcbPadding(byte[] key, byte[] data)
            throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException,
            NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
        Cipher cipher = generateEcbCipher(ALGORITHM_NAME_ECB_PADDING, Cipher.ENCRYPT_MODE, key);
        return cipher.doFinal(data);
    }

    /**
     * 用ECB模式和PKCS5Padding填充的方式 进行解密
     *
     * @param key        秘钥
     * @param cipherText 加密后的数据
     * @return 解密后的数据
     * @throws InvalidKeyException       异常
     * @throws NoSuchAlgorithmException  异常
     * @throws NoSuchProviderException   异常
     * @throws NoSuchPaddingException    异常
     * @throws IllegalBlockSizeException 异常
     * @throws BadPaddingException       异常
     */
    private static byte[] decryptEcbPadding(byte[] key, byte[] cipherText)
            throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException,
            NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException {
        Cipher cipher = generateEcbCipher(ALGORITHM_NAME_ECB_PADDING, Cipher.DECRYPT_MODE, key);
        return cipher.doFinal(cipherText);
    }


    /**
     * 用ECB模式和不填充的方式 进行加密
     *
     * @param key  秘钥
     * @param data 加密前的数据
     * @return 加密后的数据
     * @throws InvalidKeyException       异常
     * @throws NoSuchAlgorithmException  异常
     * @throws NoSuchProviderException   异常
     * @throws NoSuchPaddingException    异常
     * @throws IllegalBlockSizeException 异常
     * @throws BadPaddingException       异常
     */
    private static byte[] encryptEcbNoPadding(byte[] key, byte[] data)
            throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException,
            NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
        Cipher cipher = generateEcbCipher(ALGORITHM_NAME_ECB_NOPADDING, Cipher.ENCRYPT_MODE, key);
        return cipher.doFinal(data);
    }

    /**
     * 用ECB模式和不填充的方式 进行解密
     *
     * @param key        秘钥
     * @param cipherText 解密前的数据
     * @return 解密后的数据
     * @throws InvalidKeyException       异常
     * @throws NoSuchAlgorithmException  异常
     * @throws NoSuchProviderException   异常
     * @throws NoSuchPaddingException    异常
     * @throws IllegalBlockSizeException 异常
     * @throws BadPaddingException       异常
     */
    private static byte[] decryptEcbNoPadding(byte[] key, byte[] cipherText)
            throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException,
            NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException {
        Cipher cipher = generateEcbCipher(ALGORITHM_NAME_ECB_NOPADDING, Cipher.DECRYPT_MODE, key);
        return cipher.doFinal(cipherText);
    }

    /**
     * 生成CBC模式的cipher
     *
     * @param algorithmName 算法名称
     * @param mode          模式
     * @param key           秘钥
     * @param iv            偏移量(自定义的字符串)
     * @return {@link Cipher}
     * @throws NoSuchAlgorithmException 异常
     * @throws NoSuchProviderException  异常
     * @throws NoSuchPaddingException   异常
     * @throws InvalidKeyException      异常
     */
    private static Cipher generateCbcCipher(String algorithmName, int mode, byte[] key, byte[] iv)
            throws InvalidKeyException, InvalidAlgorithmParameterException, NoSuchAlgorithmException,
            NoSuchProviderException, NoSuchPaddingException {
        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;
    }

    /**
     * 用CBC模式和PKCS5Padding填充的方式 进行加密
     *
     * @param key  秘钥
     * @param iv   偏移量(自定义的字符串)
     * @param data 加密前的数据
     * @return 加密后的数据
     * @throws InvalidKeyException       异常
     * @throws NoSuchAlgorithmException  异常
     * @throws NoSuchProviderException   异常
     * @throws NoSuchPaddingException    异常
     * @throws IllegalBlockSizeException 异常
     * @throws BadPaddingException       异常
     */
    private static byte[] encryptCbcPadding(byte[] key, byte[] iv, byte[] data)
            throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException,
            NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException,
            InvalidAlgorithmParameterException {
        Cipher cipher = generateCbcCipher(ALGORITHM_NAME_CBC_PADDING, Cipher.ENCRYPT_MODE, key, iv);
        return cipher.doFinal(data);
    }

    /**
     * 用CBC模式和PKCS5Padding填充的方式 进行解密
     *
     * @param key        秘钥
     * @param iv         偏移量(自定义的字符串)
     * @param cipherText 解密前的数据
     * @return 解密后的数据
     * @throws InvalidKeyException       异常
     * @throws NoSuchAlgorithmException  异常
     * @throws NoSuchProviderException   异常
     * @throws NoSuchPaddingException    异常
     * @throws IllegalBlockSizeException 异常
     * @throws BadPaddingException       异常
     */
    private static byte[] decryptCbcPadding(byte[] key, byte[] iv, byte[] cipherText)
            throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException,
            NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException,
            InvalidAlgorithmParameterException {
        Cipher cipher = generateCbcCipher(ALGORITHM_NAME_CBC_PADDING, Cipher.DECRYPT_MODE, key, iv);
        return cipher.doFinal(cipherText);
    }

    /**
     * 用CBC模式和不填充的方式 进行加密
     *
     * @param key  秘钥
     * @param iv   偏移量(自定义的字符串)
     * @param data 加密前的数据
     * @return 加密后的数据
     * @throws InvalidKeyException       异常
     * @throws NoSuchAlgorithmException  异常
     * @throws NoSuchProviderException   异常
     * @throws NoSuchPaddingException    异常
     * @throws IllegalBlockSizeException 异常
     * @throws BadPaddingException       异常
     */
    private static byte[] encryptCbcNoPadding(byte[] key, byte[] iv, byte[] data)
            throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException,
            NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException,
            InvalidAlgorithmParameterException {
        Cipher cipher = generateCbcCipher(ALGORITHM_NAME_CBC_NOPADDING, Cipher.ENCRYPT_MODE, key, iv);
        return cipher.doFinal(data);
    }

    /**
     * 用ECB模式和不填充的方式 进行解密
     *
     * @param key        秘钥
     * @param iv         偏移量(自定义的字符串)
     * @param cipherText 加密后的数据
     * @return 解密后的数据
     * @throws InvalidKeyException       异常
     * @throws NoSuchAlgorithmException  异常
     * @throws NoSuchProviderException   异常
     * @throws NoSuchPaddingException    异常
     * @throws IllegalBlockSizeException 异常
     * @throws BadPaddingException       异常
     */
    private static byte[] decryptCbcNoPadding(byte[] key, byte[] iv, byte[] cipherText)
            throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException,
            NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException,
            InvalidAlgorithmParameterException {
        Cipher cipher = generateCbcCipher(ALGORITHM_NAME_CBC_NOPADDING, Cipher.DECRYPT_MODE, key, iv);
        return cipher.doFinal(cipherText);
    }

    /**
     * 生成key并且转换为16进制字符串
     *
     * @return key
     * @throws NoSuchProviderException  异常
     * @throws NoSuchAlgorithmException 异常
     */
    public static String generateKey_Hex() throws Exception {
        return HexUtils.toHexString(generateKey());
    }

    /**
     * 用CBC模式和PKCS5Padding填充的方式 进行加密
     *
     * @param key  秘钥
     * @param iv   偏移量(自定义的字符串)
     * @param data 加密数据
     * @return 加密后的转换成Hex的数据
     */
    public static String encryptCbcPaddingHex(String key, String iv, String data) throws Exception {

        String iv_hex = HexUtils.toHexString(iv.getBytes());

        return HexUtils.toHexString(encryptCbcPadding(HexUtils.fromHexString(key),
                HexUtils.fromHexString(iv_hex), data.getBytes()));
    }

    /**
     * 用CBC模式和PKCS5Padding填充的方式 进行解密
     *
     * @param key        秘钥
     * @param iv         偏移量(自定义的字符串)
     * @param cipherText 待解密数据
     * @return 解密后的数据
     */
    public static String decryptCbcPaddingHex(String key, String iv, String cipherText) throws Exception {
        return new String(decryptCbcPadding(HexUtils.fromHexString(key), iv.getBytes(),
                HexUtils.fromHexString(cipherText)));
    }

    public static void main(String[] args) throws Exception {
        String data = "{\"test\":\"湖北利川深圳\"}";
        String iv = "blade12345678910";
//        String hexKey = generateKey_Hex();
        String hexKey = "20785fae41a54c65ab95d2db1abc7f9f";
        System.out.println("hexKey===" + hexKey);
        String cipher = encryptCbcPaddingHex(hexKey, iv, data);
        System.out.println("cipher==" + cipher);
        String b = decryptCbcPaddingHex(hexKey, iv, cipher);
        System.out.println(b);
    }
}

4:Android SM4 工具类,要把 

BouncyCastleProvider.PROVIDER_NAME 贴换为 new BouncyCastleProvider()  不然报错

5:

分别在拦截器里面调用 加解密方法。hexKey 可以自己生成。iv 自己定义16位

    String hexKey = "20785fae41a54c65ab95d2db1abc7f9f";
    String iv = "blade12345678910";

加密方法:

String encryptJson = Sm4Util.encryptCbcPaddingHex(hexKey, iv, String.valueOf(json));

解密方法:

 String decryptJson = Sm4Util.decryptCbcPaddingHex(hexKey, iv, String.valueOf(data));

6:这里面就不展示拦截器里面的代码。

7:截图展示加解密后的效果。

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SM4是一种对称加密算法,可以用于Android图片文件的加密和解密。以下是一个简单的示例代码,演示如何使用SM4加密和解密图片文件: ```java import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.util.Base64; import com.tongtech.cryptolib.SM4Utils; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; public class ImageUtils { /** * 加密图片文件 * * @param context 上下文对象 * @param imagePath 图片文件路径 * @param key 密钥 * @param iv 初始向量 * @param encryptDir 加密后保存的目录 * @return 加密后的图片文件路径 * @throws Exception */ public static String encryptImage(Context context, String imagePath, String key, String iv, String encryptDir) throws Exception { // 读取图片文件 FileInputStream inputStream = new FileInputStream(imagePath); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len; while ((len = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, len); } byte[] data = outputStream.toByteArray(); inputStream.close(); outputStream.close(); // 使用SM4算法加密数据 SM4Utils sm4Utils = new SM4Utils(); sm4Utils.setSecretKey(key); sm4Utils.setIv(iv); byte[] encryptedData = sm4Utils.encryptData_ECB(data); // 将加密后的数据转换成Base64编码字符串 String base64Data = Base64.encodeToString(encryptedData, Base64.DEFAULT); // 将加密后的数据写入文件 String encryptedPath = encryptDir + "/encrypted_image.jpg"; FileOutputStream outputStream1 = new FileOutputStream(encryptedPath); outputStream1.write(base64Data.getBytes()); outputStream1.close(); return encryptedPath; } /** * 解密图片文件 * * @param context 上下文对象 * @param encryptedPath 加密后的图片文件路径 * @param key 密钥 * @param iv 初始向量 * @return 解密后的Bitmap对象 * @throws Exception */ public static Bitmap decryptImage(Context context, String encryptedPath, String key, String iv) throws Exception { // 读取加密后的数据 FileInputStream inputStream = new FileInputStream(encryptedPath); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len; while ((len = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, len); } String base64Data = outputStream.toString(); byte[] encryptedData = Base64.decode(base64Data, Base64.DEFAULT); inputStream.close(); outputStream.close(); // 使用SM4算法解密数据 SM4Utils sm4Utils = new SM4Utils(); sm4Utils.setSecretKey(key); sm4Utils.setIv(iv); byte[] data = sm4Utils.decryptData_ECB(encryptedData); // 将解密后的数据转换成Bitmap对象 Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); return bitmap; } } ``` 需要注意的是,加密和解密时使用的密钥和初始向量应该保持一致,否则解密会失败。另外,该示例中使用的是SM4算法的ECB模式,也可以使用其他模式,如CBC等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值