android(java) SM3,SM4国密算法踩坑总结

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

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

 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     }

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

java.security.NoSuchProviderException No such provider: BCgithub

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

java的话在static块中添加dom

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

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

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

研究了两天,看了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,可是版本略低呢!spa

果不其然,我打印了在我添加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 ,做者也是文中我请教的大佬。

相关文章
相关标签/搜索