1、开发环境ubuntu+eclipse+openJDK
本来想在xp下开发,但是JDK1.6中有层层限制:JCA对外出口但是JCE对外不出口,当你实现后调用Cipher会报如下错误:
Exception in thread "main" java.lang.SecurityException: JCE cannot authenticate the provider SecureProvider at javax.crypto.Cipher.getInstance(DashoA13*..) at com.ligson.test.SimpleTest.main(SimpleTest.java:19) Caused by: java.util.jar.JarException: Cannot parse file:/E:/code/itrusca/MyProvider/target/classes/ at javax.crypto.SunJCE_c.a(DashoA13*..) at javax.crypto.SunJCE_b.b(DashoA13*..) at javax.crypto.SunJCE_b.a(DashoA13*..) ... 2 more
意思是让你去用自己产生的CSR提交到SUN的CA中心(IBM旗下也有)产生一张证书,进行代码签名(据我找到的信息,他一般是不会向你颁发证书的,也许你会说BouncyCastle就有自己的Provider,但是人家不是中国的)
2、Provider的实现
package com.ligson.provider; import java.io.IOException; import java.net.URL; import java.security.AccessController; import java.security.AuthProvider; import java.security.CodeSource; import java.security.PrivilegedAction; import java.security.Provider; import java.security.SecurityPermission; import java.util.jar.JarException; import javax.security.auth.Subject; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.login.LoginException; import com.ligson.jce.impl.SM3MessageDigest; public final class SecureProvider extends AuthProvider { private static String name = "SecureProvider"; private static String info = "this is a test provider for sm2/sm3"; private static double version = 1.0d; public SecureProvider() { super(name, version, info); // this.putService(s); //授权 AccessController.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { //放入自己的基础实现类 //格式:类型.算法 put("Cipher.SM2", "com.ligson.jce.impl.SM2Cipher"); put("MessageDigest.SM3", SM3MessageDigest.class.getName()); put("Cipher.Simple", "com.ligson.provider.SimpleCipher"); put("KeyGenerator.Simple", "com.ligson.provider.SimpleKeyGenerator"); return null; } }); } private static URL getClassURL(final Class<?> clazz) { return AccessController.doPrivileged(new PrivilegedAction<URL>() { public URL run() { CodeSource cs = clazz.getProtectionDomain().getCodeSource(); return cs.getLocation(); } }); } /** * */ private static final long serialVersionUID = 1L; public String getName() { return name; } public String getInfo() { return info; } public double getVersion() { return version; } public static interface Tst { } @Override public void login(Subject subject, CallbackHandler handler) throws LoginException { SecurityManager sm = System.getSecurityManager(); sm.checkPermission(new SecurityPermission("authProvider." + this.getName())); } @Override public void logout() throws LoginException { // TODO Auto-generated method stub } @Override public void setCallbackHandler(CallbackHandler handler) { // TODO Auto-generated method stub }; }
3、SimpleCipher的实现,原理很简单,就是把输入的byte[]的每一个byte元素加上一个随机数,解密的时候再减去
package com.ligson.provider; import java.security.AlgorithmParameters; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.Key; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.CipherSpi; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.crypto.ShortBufferException; public class SimpleCipher extends CipherSpi { private int mode; private Key key; private byte[] in; @Override protected byte[] engineDoFinal(byte[] arg0, int arg1, int arg2) throws IllegalBlockSizeException, BadPaddingException { return implDoFinal(); } @Override protected int engineDoFinal(byte[] arg0, int arg1, int arg2, byte[] arg3, int arg4) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { return 0; } @Override protected int engineGetBlockSize() { return 0; } @Override protected byte[] engineGetIV() { return null; } @Override protected int engineGetOutputSize(int arg0) { return 0; } @Override protected AlgorithmParameters engineGetParameters() { return null; } @Override protected void engineInit(int arg0, Key arg1, SecureRandom arg2) throws InvalidKeyException { implInit(arg0, arg1); } @Override protected void engineInit(int arg0, Key arg1, AlgorithmParameterSpec arg2, SecureRandom arg3) throws InvalidKeyException, InvalidAlgorithmParameterException { implInit(arg0, arg1); } @Override protected void engineInit(int arg0, Key arg1, AlgorithmParameters arg2, SecureRandom arg3) throws InvalidKeyException, InvalidAlgorithmParameterException { implInit(arg0, arg1); } @Override protected void engineSetMode(String arg0) throws NoSuchAlgorithmException { } @Override protected void engineSetPadding(String arg0) throws NoSuchPaddingException { } @Override protected byte[] engineUpdate(byte[] arg0, int arg1, int arg2) { return implUpdate(arg0, arg1, arg2); } @Override protected int engineUpdate(byte[] arg0, int arg1, int arg2, byte[] arg3, int arg4) throws ShortBufferException { return 0; } private void implInit(int mode, Key key) { this.mode = mode; if (key instanceof SimpleKey) { this.key = key; } else { throw new RuntimeException("key invalid!"); } } private byte[] implUpdate(byte[] in, int offset, int len) { this.in = in; return in; } private byte[] implDoFinal() { SimpleKey simpleKey = (SimpleKey) key; if (mode == Cipher.ENCRYPT_MODE) { for (int i = 0; i < in.length; i++) { in[i] = (byte) (in[i] + simpleKey.offset); } } else if (mode == Cipher.DECRYPT_MODE) { for (int i = 0; i < in.length; i++) { in[i] = (byte) (in[i] - simpleKey.offset); } } else { throw new RuntimeException("mode must be encrypt or decrypt!"); } return in; } public void init(int mode, Key key) { implInit(mode, key); } public void update(byte[] in, int offset, int len) { implUpdate(in, offset, len); } public byte[] doFinal() { return implDoFinal(); } }
4、SimpleKey(只是一个简单的对称密钥)的实现,里面只保存随机的偏移量、长度等
package com.ligson.provider; import java.security.SecureRandom; import javax.crypto.SecretKey; public class SimpleKey implements SecretKey { protected int len; protected SecureRandom random; protected int offset; SimpleKey(SecureRandom random, int keySize,int offset) { this.len = keySize; this.random = random; this.offset = offset; } @Override public String getAlgorithm() { return "Simple"; } @Override public String getFormat() { return ""; } @Override public byte[] getEncoded() { byte[] b = new byte[len]; random.nextBytes(b); return b; } }
5、SimpleKeyGenerator的实现
package com.ligson.provider; import java.security.InvalidAlgorithmParameterException; import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; import javax.crypto.KeyGeneratorSpi; import javax.crypto.SecretKey; public class SimpleKeyGenerator extends KeyGeneratorSpi { private SecureRandom random = new SecureRandom(); private int keySize = 128; private int offset = 3; @Override protected SecretKey engineGenerateKey() { offset = random.nextInt(); return new SimpleKey(random,keySize,offset); } @Override protected void engineInit(SecureRandom secureRandom) { this.random = secureRandom; } @Override protected void engineInit(AlgorithmParameterSpec arg0, SecureRandom arg1) throws InvalidAlgorithmParameterException { throw new InvalidAlgorithmParameterException("no support operation"); } @Override protected void engineInit(int keySize, SecureRandom secureRandom) { this.keySize = keySize; this.random = secureRandom; } }
6、Provider的测试程序
SecureProvider provider = new SecureProvider(); Security.addProvider(provider); KeyGenerator generator = KeyGenerator.getInstance("Simple",provider); System.out.println(generator); generator.init(512); SecretKey secretKey = generator.generateKey(); System.out.println(Arrays.toString(secretKey.getEncoded())); byte[] plain = "password".getBytes(); System.out.println(Arrays.toString(plain)); Cipher cipher = Cipher.getInstance("Simple"); cipher.init(Cipher.ENCRYPT_MODE,secretKey); cipher.update(plain); byte[] result = cipher.doFinal(); System.out.println(Arrays.toString(result)); cipher.init(Cipher.DECRYPT_MODE,secretKey); cipher.update(result); byte[] result2 = cipher.doFinal(); System.out.println(Arrays.toString(result2)); System.out.println(Arrays.equals(result2,plain));
结果如下: