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 ,做者也是文中我請教的大佬。

相關文章
相關標籤/搜索