zoukankan      html  css  js  c++  java
  • android(java) SM3,SM4国密算法踩坑总结

    好久没在博客园写随笔了,来说说我最近在做的人脸支付使用国密算法加密时遇到的一些坑。

    SM4加密第一步,生成"BC"provider,"SM4"算法的key

     1 public static String generateKey() {
     2         try {
     3             //获取到当前系统中的 提供者 和提供者支持的算法。
     4             /*Provider[] providers = Security.getProviders();
     5             for (Provider provider2 : providers) {
     6                 System.err.println(provider2);
     7                 Set<Map.Entry<Object, Object>> entrySet = provider2.entrySet();
     8                 for (Map.Entry<Object, Object> entry : entrySet) {
     9                     System.out.println(entry.getKey() +"  "+ entry.getValue());
    10                 }
    11             }*/
    12             KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM, BouncyCastleProvider.PROVIDER_NAME);
    13             kg.init(64, new SecureRandom());
    14             return new String(Hex.encodeHex(kg.generateKey().getEncoded())).toUpperCase();
    15         } catch (Exception e) {
    16             e.printStackTrace();
    17         }
    18         return null;
    19     }

    运行这个方法,我遇到的第一个坑:

    java.security.NoSuchProviderException No such provider: BC

    此异常我通过各种博客,github问一些开源作者,也都是给出这样的解决办法

    java的话在static块中添加

    1     static {
    2         Security.addProvider(new BouncyCastleProvider());
    3     }

    android的话在加密方法调用前使用这句话即可。

    然而我再次运行,抛出另一个algorithmexception:no such algorithm: SM4 for provider BC

    研究了两天,看了BCProvider类的源码,无果,误打误撞想着从当前系统remove掉BCProvider会怎么样,居然解决了,代码如下:

    1     Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
    2         if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null){
    3             Log.i("sys","运行环境没有BouncyCastleProvider");
    4             Security.addProvider(new BouncyCastleProvider());
    5         }
    6         String semKey = SM4Util.generateKey();

    然后就想为啥这样子能解决,会不会在我android应用启动的时候已经加载了BCProvider,但是版本略低呢!

    果不其然,我打印了在我添加BCProvider之前那个假“BCprovider”的版本

    1     if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) != null){
    2             double version = Security.getProvider(BouncyCastleProvider.PROVIDER_NAME).getVersion();
    3             Log.i("sys","原有version="+version);
    4         }

    而我使用的下载的jar包是jdk_15on_160的

    这便证实了我的想法,后来我去请教了大佬,结论如下

    好了,问题至此解决,下面贴出android和java国密算法的代码

    android:

     1 public class SM3Util {
     2 
     3 
     4     public static String hash(String data, String encoding) throws Exception {
     5         SM3Digest digest = new SM3Digest();
     6         byte[] source = data.getBytes(encoding);
     7         digest.update(source, 0, source.length);
     8         byte[] update = new byte[digest.getDigestSize()];
     9         digest.doFinal(update, 0);
    10         return ByteUtils.toHexString(update).toUpperCase();
    11     }
    12 
    13     public static byte[] byteHash(String data, String encoding) throws Exception {
    14         SM3Digest digest = new SM3Digest();
    15         byte[] source = data.getBytes(encoding);
    16         digest.update(source, 0, source.length);
    17         byte[] update = new byte[digest.getDigestSize()];
    18         digest.doFinal(update, 0);
    19         return update;
    20     }
    21 
    22 }
      1 public class SM4Util {
      2 
      3     public static final int KEY_SIZE = 128;
      4 
      5     public static final String ALGORITHM = "SM4";
      6 
      7     public static final String IV = "根据自己的项目定义";
      8 
      9     public static final String ALGORITHM_ECB_PADDING = "SM4/ECB/PKCS7Padding";
     10 
     11     public static final String ALGORITHM_CBC_PADDING = "SM4/CBC/PKCS7Padding";
     12 
     13 
     14     public static byte[] encryptECBToByte(byte[] data, String keyStr) {
     15         try {
     16             Cipher cipher = Cipher.getInstance(ALGORITHM_ECB_PADDING, BouncyCastleProvider.PROVIDER_NAME);
     17             Key key = new SecretKeySpec(keyStr.getBytes(), ALGORITHM);
     18             cipher.init(Cipher.ENCRYPT_MODE, key);
     19             byte[] enBytes = cipher.doFinal(data);
     20             return enBytes;
     21         } catch (Exception e) {
     22             e.printStackTrace();
     23         }
     24         return null;
     25     }
     26 
     27     public static String encryptECB(String data, String keyStr, String encoding) {
     28         try {
     29             Cipher cipher = Cipher.getInstance(ALGORITHM_ECB_PADDING, BouncyCastleProvider.PROVIDER_NAME);
     30             Key key = new SecretKeySpec(keyStr.getBytes(), ALGORITHM);
     31             cipher.init(Cipher.ENCRYPT_MODE, key);
     32             byte[] enBytes = cipher.doFinal(data.getBytes(encoding));
     33             Base64Encoder base64Encoder = new Base64Encoder();
     34             return base64Encoder.encode(enBytes);
     35         } catch (Exception e) {
     36             e.printStackTrace();
     37         }
     38         return null;
     39     }
     40 
     41     public static byte[] decryptECBToByte(byte[] data, String keyStr) {
     42         try {
     43             Cipher cipher = Cipher.getInstance(ALGORITHM_ECB_PADDING, BouncyCastleProvider.PROVIDER_NAME);
     44             Key key = new SecretKeySpec(keyStr.getBytes(), ALGORITHM);
     45             cipher.init(Cipher.DECRYPT_MODE, key);
     46             byte[] deBytes = cipher.doFinal(data);
     47             return deBytes;
     48         } catch (Exception e) {
     49             e.printStackTrace();
     50         }
     51         return null;
     52     }
     53 
     54     public static String decryptECB(String data, String keyStr, String encoding) {
     55         try {
     56             Cipher cipher = Cipher.getInstance(ALGORITHM_ECB_PADDING, BouncyCastleProvider.PROVIDER_NAME);
     57             Key key = new SecretKeySpec(keyStr.getBytes(), ALGORITHM);
     58             cipher.init(Cipher.DECRYPT_MODE, key);
     59 //            byte[] deBytes = cipher.doFinal(Base64.decodeBase64(data));
     60             Base64Encoder base64Encoder = new Base64Encoder();
     61             byte[] deBytes = cipher.doFinal(base64Encoder.decode(data));
     62             return new String(deBytes, encoding);
     63         } catch (Exception e) {
     64             e.printStackTrace();
     65         }
     66         return null;
     67     }
     68 
     69     public static byte[] encryptCBCToByte(byte[] data, String keyStr) {
     70         try {
     71             Cipher cipher = Cipher.getInstance(ALGORITHM_CBC_PADDING, BouncyCastleProvider.PROVIDER_NAME);
     72             Key key = new SecretKeySpec(keyStr.getBytes(), ALGORITHM);
     73             IvParameterSpec ivSpec = new IvParameterSpec(IV.getBytes());
     74             AlgorithmParameterSpec paramSpec = ivSpec;
     75             cipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
     76             byte[] enBytes = cipher.doFinal(data);
     77             return enBytes;
     78         } catch (Exception e) {
     79             e.printStackTrace();
     80         }
     81         return null;
     82     }
     83 
     84     public static String encryptCBC(String data, String keyStr, String encoding) {
     85         try {
     86             Cipher cipher = Cipher.getInstance(ALGORITHM_CBC_PADDING, BouncyCastleProvider.PROVIDER_NAME);
     87             Key key = new SecretKeySpec(keyStr.getBytes(), ALGORITHM);
     88             IvParameterSpec ivSpec = new IvParameterSpec(IV.getBytes());
     89             AlgorithmParameterSpec paramSpec = ivSpec;
     90             cipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
     91             byte[] enBytes = cipher.doFinal(data.getBytes(encoding));
     92             Base64Encoder base64Encoder = new Base64Encoder();
     93             return base64Encoder.encode(enBytes);
     94         } catch (Exception e) {
     95             e.printStackTrace();
     96         }
     97         return null;
     98     }
     99 
    100     public static byte[] decryptCBCToByte(byte[] data, String keyStr) {
    101         try {
    102             Cipher cipher = Cipher.getInstance(ALGORITHM_CBC_PADDING, BouncyCastleProvider.PROVIDER_NAME);
    103             Key key = new SecretKeySpec(keyStr.getBytes(), ALGORITHM);
    104             IvParameterSpec ivSpec = new IvParameterSpec(IV.getBytes());
    105             AlgorithmParameterSpec paramSpec = ivSpec;
    106             cipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
    107             byte[] deBytes = cipher.doFinal(data);
    108             return deBytes;
    109         } catch (Exception e) {
    110             e.printStackTrace();
    111         }
    112         return null;
    113     }
    114 
    115     public static String decryptCBC(String data, String keyStr, String encoding) {
    116         try {
    117             Cipher cipher = Cipher.getInstance(ALGORITHM_CBC_PADDING, BouncyCastleProvider.PROVIDER_NAME);
    118             Key key = new SecretKeySpec(keyStr.getBytes(), ALGORITHM);
    119             IvParameterSpec ivSpec = new IvParameterSpec(IV.getBytes());
    120             AlgorithmParameterSpec paramSpec = ivSpec;
    121             cipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
    122 //            byte[] deBytes = cipher.doFinal(Base64.decodeBase64(data));
    123             Base64Encoder base64Encoder = new Base64Encoder();
    124             byte[] deBytes = cipher.doFinal(base64Encoder.decode(data));
    125             return new String(deBytes, encoding);
    126         } catch (Exception e) {
    127             e.printStackTrace();
    128         }
    129         return null;
    130     }
    131 
    132     public static String generateKey() {
    133         try {
    134             //获取到当前系统中的 提供者 和提供者支持的算法。
    135             /*Provider[] providers = Security.getProviders();
    136             for (Provider provider2 : providers) {
    137                 System.err.println(provider2);
    138                 Set<Map.Entry<Object, Object>> entrySet = provider2.entrySet();
    139                 for (Map.Entry<Object, Object> entry : entrySet) {
    140                     System.out.println(entry.getKey() +"  "+ entry.getValue());
    141                 }
    142             }*/
    143             KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM, BouncyCastleProvider.PROVIDER_NAME);
    144             kg.init(64, new SecureRandom());
    145             return new String(Hex.encodeHex(kg.generateKey().getEncoded())).toUpperCase();
    146         } catch (Exception e) {
    147             e.printStackTrace();
    148         }
    149         return null;
    150     }
    151 
    152 }

    java请参考 https://github.com/ZZMarquis/gmhelper ,作者也是文中我请教的大佬。

     
  • 相关阅读:
    我想操作的是利用SqlDataAdapter的几个Command属性(InsertCommand,UpdateCommand,DeleteCommand)来更新数据库
    有两个数据库A和B,数据库A中有表a,如何把表a映射到数据库B中,sql 2005
    代码生成器
    IWorkSpace接口介绍
    空间数据库介绍
    IGeoFeatureLayer
    IFeatureLayer
    Python ML环境搭建与学习资料推荐
    Python ML环境搭建与学习资料推荐
    TypeError: Can not convert a float32 into a Tensor or Operation.
  • 原文地址:https://www.cnblogs.com/cherrylv/p/10688487.html
Copyright © 2011-2022 走看看