ITeye Java编程 Spring框架 Ajax技术 agile敏捷软件开发 ruby on rails实践 - ITeye做最棒的软件开发交流社区 - 乐虎国际|授权平台 我的博客 https://lobin.iteye.com zh-CN Copyright 2003-2019, ITeye.com http://blogs.law.harvard.edu/tech/rss ITeye - 软件开发交流社区 ITeye Java编程 Spring框架 Ajax技术 agile敏捷软件开发 ruby on rails实践 - ITeye做最棒的软件开发交流社区 - 乐虎国际|授权平台 Ribbon是微服务的一个核心基础组件,提供多协议HTTP、TCP以及UDP的服务调用RPC功能以及负载均衡功能。 Ribbon:一个客户端IPC(Inter Process Communication)库,RPC(Remote Procedure Calls)库。支持负载均衡、故障容错、多协议支持:HTTP, TCP, UDP,支持异步(asynchronous)以及reactive模型、Caching 以及batching。   举例某个api应用,运行了两个实例(部署了2台机器),这个应用提供了两个api: 1、/test 2、/test/{version} 这两个api都有个参数data,/test/{version}还有个@PathVariable的version参数。 /test定义如下: @ResponseBody @RequestMapping(value = "test") public String test(@RequestParam String data) { return data; } /test/{version}定义如下: @ResponseBody @RequestMapping(value = "test/{version}") public String testvn(@PathVariable String version, @RequestParam String data) { return data + ";version=" + version; } 就是两个普通的api,和我们以前写的api是一样的,可以直接请求: http://localhost:8081/test?data=aaa http://localhost:8082/test?data=aaa   http://localhost:8081/test/1.0?data=aaa http://localhost:8082/test/1.0?data=aaa   通过ribbon调用这俩个api服务:   注解方式: public interface TestService { @Http( method = Http.HttpMethod.GET, uri = "/test?data={data}" ) RibbonRequest<ByteBuf> test(@Var("data") String data); @Http( method = Http.HttpMethod.GET, uri = "/test/{version}?data={data}" ) RibbonRequest<ByteBuf> testvn(@Var("version") String version, @Var("data") String data); } 通过ribbon调用/test服务: @Test public void test11() { ConfigurationManager.getConfigInstance().setProperty("TestService.ribbon." + CommonClientConfigKey.MaxAutoRetriesNextServer, "3"); ConfigurationManager.getConfigInstance().setProperty("TestService.ribbon." + CommonClientConfigKey.ListOfServers, "localhost:8082,localhost:8081"); TestService testService = Ribbon.from(TestService.class); RibbonRequest<ByteBuf> request = testService.test("aaa"); ByteBuf result0 = request.execute(); ByteBuffer buf = result0.nioBuffer(); byte[] bytes = new byte[buf.remaining()]; buf.get(bytes); System.out.println(new String(bytes)); } 通过ribbon调用/test/{version}服务: @Test public void test21() { ConfigurationManager.getConfigInstance().setProperty("TestService.ribbon." + CommonClientConfigKey.MaxAutoRetriesNextServer, "3"); ConfigurationManager.getConfigInstance().setProperty("TestService.ribbon." + CommonClientConfigKey.ListOfServers, "localhost:8082,localhost:8081"); TestService testService = Ribbon.from(TestService.class); RibbonRequest<ByteBuf> request = testService.testvn("1.0", "aaa"); ByteBuf result0 = request.execute(); ByteBuffer buf = result0.nioBuffer(); byte[] bytes = new byte[buf.remaining()]; buf.get(bytes); System.out.println(new String(bytes)); }   Ribbon还提供了一个template方式来请求HTTP资源,Template方式可参考文章: https://lobin.iteye.com/blog/1576159 Ribbon负载均衡例子参考文章: https://lobin.iteye.com/blog/1576159   1、https://github.com/Netflix/ribbon

已有 0 人发表留言,猛击->>这里<<-参与讨论


ITeye推荐



]]>
Thu, 14 Feb 2019 01:44:35 +0800 https://lobin.iteye.com/blog/2437515 https://lobin.iteye.com/blog/2437515
ITeye Java编程 Spring框架 Ajax技术 agile敏捷软件开发 ruby on rails实践 - ITeye做最棒的软件开发交流社区 - 乐虎国际|授权平台 >tree . /F Folder PATH listing for volume D Volume serial number is F075-351A └───com     └───jx             com_jx_Object.cpp             com_jx_Object.hpp             com_jx_Object.obj             libobj.dll             libobj.exp             libobj.lib             Object.class             Object.java             ObjectTest.java   package com.jx; public class Object { private int index; public Object(int index) { this.index = index; } public int index() { return index; } public native int addr(); static { System.loadLibrary("libobj"); } } >javac com\jx\Object.java   >javah -jni -d com\jx com.jx.Object  com_jx_Object.hpp: /* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_jx_Object */ #ifndef _Included_com_jx_Object #define _Included_com_jx_Object #ifdef __cplusplus extern "C" { #endif /* * Class: com_jx_Object * Method: addr * Signature: ()I */ JNIEXPORT jint JNICALL Java_com_jx_Object_addr (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif com_jx_Object.cpp: #include <stdio.h> #include "com_jx_Object.hpp" JNIEXPORT jint JNICALL Java_com_jx_Object_addr (JNIEnv *env, jobject jobj) { jlong addr = reinterpret_cast<jlong>(jobj); printf("Java_com_jx_Object_addr.\n"); printf("obj addr: %ld\n", jobj); printf("obj addr: %ld\n", &jobj); printf("obj addr: %ld\n", addr); return 0; }   >cl /GR /GX /W3 /ID:\usr\bin\jdk1.8.0_101\include /ID:\usr\bin\jdk1.8.0_101\include\win32 /c /Fo.\ *.cpp   >link /DLL /OUT:.\libobj.dll .\*.obj 也可以使用以下命令一次就生成库文件 # 也可以使用以下命令一次就生成库文件: >cl /ID:\usr\bin\jdk1.8.0_101\include /ID:\usr\bin\jdk1.8.0_101\include\win32 /LD com_jx_Object.c 将生成的库文件libobj.dll放在path目录下   package com.jx; import java.lang.reflect.Field; import sun.misc.Unsafe; public class ObjectTest { public static void main(String[] args) throws Throwable { String libPath = System.getProperty("java.library.path"); System.out.println(libPath); Unsafe unsafe = getUnsafe(); Object obj = new Object(12345); Field field = Object.class.getDeclaredField("index"); long addr = location(obj); System.out.println("obj addr: " + obj.hashCode()); System.out.println("obj addr: " + addr); System.out.println("obj addr: " + unsafe.getAddress(addr)); long valueOffset = unsafe.objectFieldOffset(field); System.out.println("index offset: " + valueOffset); int value2 = unsafe.getInt(obj, valueOffset); System.out.println("index: " + value2); value2 = unsafe.getInt(addr + valueOffset); System.out.println("index: " + value2); obj.addr(); } public static long location(Object object) throws Throwable { Unsafe unsafe = getUnsafe(); Object[] array = new Object[] {object}; long baseOffset = unsafe.arrayBaseOffset(Object[].class); int addressSize = unsafe.addressSize(); long location; switch (addressSize) { case 4: location = unsafe.getInt(array, baseOffset); break; case 8: location = unsafe.getLong(array, baseOffset); break; default: throw new Error("unsupported address size: " + addressSize); } return (location); } private static Unsafe getUnsafe() throws Throwable { Class unsafeClass = Unsafe.class; for (Field f : unsafeClass.getDeclaredFields()) { if ("theUnsafe".equals(f.getName())) { f.setAccessible(true); return (Unsafe) f.get(null); } } throw new IllegalAccessException("no declared field: theUnsafe"); } } 运行结果 obj addr: 5433634 obj addr: 46840104 obj addr: 695505153 index offset: 8 index: 12345 index: 12345 Java_com_jx_Object_addr. obj addr: 10157232 obj addr: 10157172 obj addr: 10157232          

已有 0 人发表留言,猛击->>这里<<-参与讨论


ITeye推荐



]]>
Sun, 27 Jan 2019 03:23:40 +0800 https://lobin.iteye.com/blog/2437111 https://lobin.iteye.com/blog/2437111
ITeye Java编程 Spring框架 Ajax技术 agile敏捷软件开发 ruby on rails实践 - ITeye做最棒的软件开发交流社区 - 乐虎国际|授权平台   private static PrivateKey privateKey = null; private static PublicKey publicKey = null; @BeforeClass public static void init() { KeyPairGenerator keyPairGenerator = null; try { keyPairGenerator = KeyPairGenerator.getInstance("DSA"); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } keyPairGenerator.initialize(1024, new SecureRandom()); KeyPair keyPair = keyPairGenerator.generateKeyPair(); privateKey = keyPair.getPrivate(); // sun.security.ec.ECPrivateKeyImpl publicKey = keyPair.getPublic(); // sun.security.ec.ECPublicKeyImpl byte[] privateKeyEncoded = ((Key) privateKey).getEncoded(); byte[] publicKeyEncoded = ((Key) publicKey).getEncoded(); System.out.println("private key: " + Base64.byteArrayToBase64(privateKeyEncoded)); System.out.println("public key: " + Base64.byteArrayToBase64(publicKeyEncoded)); }   @org.junit.Test public void test() { String message = "13120983870"; // String message = "13120983870222222222"; System.out.println(message); KeyFactory keyFactory = null; try { keyFactory = KeyFactory.getInstance("DSA"); } catch (NoSuchAlgorithmException e) { Assert.fail("no such algorithm: " + e.getMessage()); } // 签名 Signature signature = null; try { signature = Signature.getInstance("SHA256withDSA"); // NONEwithDSA, SHA256withDSA } catch (NoSuchAlgorithmException e) { Assert.fail("no such algorithm: " + e.getMessage()); } try { signature.initSign(privateKey); } catch (InvalidKeyException e) { Assert.fail("invalid key: " + e.getMessage()); } byte[] sign = null; try { signature.update(message.getBytes()); sign = signature.sign(); } catch (SignatureException e) { e.printStackTrace(); Assert.fail("signature: " + e.getMessage()); } System.out.println("signature: " + Base64.byteArrayToBase64(sign)); // 验证 try { signature.initVerify(publicKey); } catch (InvalidKeyException e) { Assert.fail("invalid key: " + e.getMessage()); } try { signature.update(message.getBytes()); boolean result = signature.verify(sign); Assert.assertTrue(result); } catch (SignatureException e) { Assert.fail("signature: " + e.getMessage()); } }   private key: MIIBSwIBADCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoEFgIUWljb9g4BGWyIIwY9IbL2GbrrSeY= public key: MIIBtzCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYQAAoGAGWINaQe4sr9eIFMZk6TMkWxwufiClPTerjSH/KBpU86RDrzOALu+graaXFJdhM1G03CSnM7JItMzIzzLuosVMNj/FVxUSC/utLlAajdlQ3TNP2ZEtLFvBw8YKewUbfXoGCfGcbnPRcPBYpkoj3/lhIhg0u06na1ZFD/soH8JWEo= 13120983870 signature: MCwCFHSq4vK8GPOt+vyChr48ubF3YSCmAhRrIUKJHhpYhqKSJq81OV52g1wqvw==    

已有 0 人发表留言,猛击->>这里<<-参与讨论


ITeye推荐



]]>
Fri, 18 Jan 2019 23:09:57 +0800 https://lobin.iteye.com/blog/2436798 https://lobin.iteye.com/blog/2436798
ITeye Java编程 Spring框架 Ajax技术 agile敏捷软件开发 ruby on rails实践 - ITeye做最棒的软件开发交流社区 - 乐虎国际|授权平台   private static PrivateKey privateKey = null; private static PublicKey publicKey = null; @BeforeClass public static void init() { KeyPairGenerator keyPairGenerator = null; try { keyPairGenerator = KeyPairGenerator.getInstance("EC"); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } keyPairGenerator.initialize(256, new SecureRandom()); KeyPair keyPair = keyPairGenerator.generateKeyPair(); privateKey = keyPair.getPrivate(); // sun.security.ec.ECPrivateKeyImpl publicKey = keyPair.getPublic(); // sun.security.ec.ECPublicKeyImpl byte[] privateKeyEncoded = ((Key) privateKey).getEncoded(); byte[] publicKeyEncoded = ((Key) publicKey).getEncoded(); System.out.println("private key: " + Base64.byteArrayToBase64(privateKeyEncoded)); System.out.println("public key: " + Base64.byteArrayToBase64(publicKeyEncoded)); }   @org.junit.Test public void test() { String message = "13120983870"; System.out.println(message); KeyFactory keyFactory = null; try { keyFactory = KeyFactory.getInstance("EC"); } catch (NoSuchAlgorithmException e) { Assert.fail("no such algorithm: " + e.getMessage()); } // 签名 Signature signature = null; try { signature = Signature.getInstance("NONEwithECDSA"); } catch (NoSuchAlgorithmException e) { Assert.fail("no such algorithm: " + e.getMessage()); } try { signature.initSign(privateKey); } catch (InvalidKeyException e) { Assert.fail("invalid key: " + e.getMessage()); } byte[] sign = null; try { signature.update(message.getBytes()); sign = signature.sign(); } catch (SignatureException e) { Assert.fail("signature: " + e.getMessage()); } System.out.println("signature: " + Base64.byteArrayToBase64(sign)); // 验证 try { signature.initVerify(publicKey); } catch (InvalidKeyException e) { Assert.fail("invalid key: " + e.getMessage()); } try { signature.update(message.getBytes()); boolean result = signature.verify(sign); Assert.assertTrue(result); } catch (SignatureException e) { Assert.fail("signature: " + e.getMessage()); } }     private key: MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCCo4Ko3RblXEVy85V4P1ODvLUOAXb2sKvtJmkOV5/HUHQ== public key: MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE6NjtyqaRPShUnTn3OrM9CNnIxKHf3yWv4iFR/LPCcCTfnzGvIb3n/9REss3wjbeBNpZBFStPsYbY+iPWXA3ASw== 13120983870 signature: MEUCIQCse/HImkyfODAdG8Xz0CKc3MSwsLGjY7ObKnlrgMKudAIgWDXfeJ9I9OtwqUuzIDwc148M9gDCXVYikB+0OGNlvBw=    

已有 0 人发表留言,猛击->>这里<<-参与讨论


ITeye推荐



]]>
Fri, 18 Jan 2019 22:40:57 +0800 https://lobin.iteye.com/blog/2436797 https://lobin.iteye.com/blog/2436797
ITeye Java编程 Spring框架 Ajax技术 agile敏捷软件开发 ruby on rails实践 - ITeye做最棒的软件开发交流社区 - 乐虎国际|授权平台  参考椭圆曲线加密:elliptic curve cryptography (ECC), 这里的椭圆曲线:elliptic curve(EC)。   使用公钥加密,再使用私钥解密。不像RSA,既可以使用公钥加密,再使用私钥解密,也可以私钥加密,再使用公钥解密   private static Provider provider = null; private static BCECPrivateKey privateKey = null; private static byte[] privateKeyEncoded1 = null; private static BCECPublicKey publicKey = null; private static byte[] publicKeyEncoded1 = null;   @BeforeClass public static void init() /* throws NoSuchAlgorithmException */ { init0(); }   public static void init0() /* throws NoSuchAlgorithmException */ { provider = new BouncyCastleProvider(); // provider = new BouncyCastlePQCProvider(); KeyPairGenerator keyPairGenerator = null; try { keyPairGenerator = KeyPairGenerator.getInstance("EC", provider); // sun.security.rsa.RSAKeyPairGenerator } catch (NoSuchAlgorithmException e) { Assert.fail("no such algorithm: " + e.getMessage()); } keyPairGenerator.initialize(256, new SecureRandom()); KeyPair keyPair1 = keyPairGenerator.generateKeyPair(); privateKey = (BCECPrivateKey) keyPair1.getPrivate(); publicKey = (BCECPublicKey) keyPair1.getPublic(); privateKeyEncoded1 = privateKey.getEncoded(); publicKeyEncoded1 = publicKey.getEncoded(); System.out.println("private key: " + Base64.byteArrayToBase64(privateKeyEncoded1)); System.out.println("public key: " + Base64.byteArrayToBase64(publicKeyEncoded1)); }   /** * 使用公钥加密,再使用私钥解密 */ @Test public void test1() { String message = "13120983870"; System.out.println(message); IESCipher.ECIESwithAES cipher1 = new IESCipher.ECIESwithAES(); try { cipher1.engineInit(Cipher.ENCRYPT_MODE, publicKey, new SecureRandom()); } catch (InvalidKeyException e) { Assert.fail("invalid key: " + e.getMessage()); } byte[] encryption1 = null; try { encryption1 = cipher1.engineDoFinal(message.getBytes(), 0, message.getBytes().length); } catch (IllegalBlockSizeException e) { Assert.fail("illegal block size: " + e.getMessage()); } catch (BadPaddingException e) { Assert.fail("bad padding: " + e.getMessage()); } System.out.println("encryption: " + Base64.byteArrayToBase64(encryption1)); cipher1 = new IESCipher.ECIESwithAES(); try { cipher1.engineInit(Cipher.DECRYPT_MODE, privateKey, new SecureRandom()); } catch (InvalidKeyException e) { Assert.fail("invalid key: " + e.getMessage()); } byte[] decryption1 = null; try { decryption1 = cipher1.engineDoFinal(encryption1, 0, encryption1.length); } catch (IllegalBlockSizeException e) { Assert.fail("illegal block size: " + e.getMessage()); } catch (BadPaddingException e) { Assert.fail("bad padding: " + e.getMessage()); } System.out.println("decryption: " + new String(decryption1) + ", base64:" + Base64.byteArrayToBase64(decryption1)); }   private key: MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgQ4vAWWNYMncNYX/kkgxPhUullJk4UR5hTEW1krcqD32gCgYIKoZIzj0DAQehRANCAATs04Bcawzubw4ozfPRhkZpykWw6TErFPhIwOYihY/RrbaiaIGJJdvbIpxm3D+YqFcnSSbTH5WXrxpQToXiUPtc public key: MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE7NOAXGsM7m8OKM3z0YZGacpFsOkxKxT4SMDmIoWP0a22omiBiSXb2yKcZtw/mKhXJ0km0x+Vl68aUE6F4lD7XA== 13120983870 encryption: BK8kO9AQoMYqTK8/BedPndCfVPpxhuvfSxUHM0UDNeWNV6RsaDOI0/XTC/5BGIkbt40JN7/T8wY9NfDZYx/jye5w09aqt90TIzBpBL7MC1jgBieji433pu2ZzhSizVwJ9QCt0zc= decryption: 13120983870, base64:MTMxMjA5ODM4NzA=   private void encryptAndDecrypt(String message, PrivateKey privateKey, PublicKey publicKey) { IESCipher.ECIESwithAES cipher1 = new IESCipher.ECIESwithAES(); try { cipher1.engineInit(Cipher.ENCRYPT_MODE, publicKey, new SecureRandom()); } catch (InvalidKeyException e) { Assert.fail("invalid key: " + e.getMessage()); } byte[] encryption1 = null; try { encryption1 = cipher1.engineDoFinal(message.getBytes(), 0, message.getBytes().length); } catch (IllegalBlockSizeException e) { Assert.fail("illegal block size: " + e.getMessage()); } catch (BadPaddingException e) { Assert.fail("bad padding: " + e.getMessage()); } System.out.println("encryption: " + Base64.byteArrayToBase64(encryption1)); cipher1 = new IESCipher.ECIESwithAES(); try { cipher1.engineInit(Cipher.DECRYPT_MODE, privateKey, new SecureRandom()); } catch (InvalidKeyException e) { Assert.fail("invalid key: " + e.getMessage()); } byte[] decryption1 = null; try { decryption1 = cipher1.engineDoFinal(encryption1, 0, encryption1.length); } catch (IllegalBlockSizeException e) { Assert.fail("illegal block size: " + e.getMessage()); } catch (BadPaddingException e) { Assert.fail("bad padding: " + e.getMessage()); } System.out.println("decryption: " + new String(decryption1) + ", base64:" + Base64.byteArrayToBase64(decryption1)); }   @Test public void test_1() { String privKey = "MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQg9ye6MPlsZbIKD3hwqWebMOkmcKHlk0NEmTbPKQDZxe2gCgYIKoZIzj0DAQehRANCAARZXl/Wn+3uVSyk/VDncYFNazAjPMEBXEwS/iWy0hwidaU3t3OrYXVMsE5xqx7qtgmBu0/dbCdyUmwMVL5CclFq"; String pubKey = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWV5f1p/t7lUspP1Q53GBTWswIzzBAVxMEv4lstIcInWlN7dzq2F1TLBOcase6rYJgbtP3WwnclJsDFS+QnJRag=="; byte[] privateKeyEncoded = Base64.base64ToByteArray(privKey); byte[] publicKeyEncoded = Base64.base64ToByteArray(pubKey); String message = "13120983870"; System.out.println(message); PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKeyEncoded); ECKeyFactorySpi keyFactory = new ECKeyFactorySpi(); PrivateKey privateKey = null; try { privateKey = keyFactory.engineGeneratePrivate(pkcs8KeySpec); } catch (InvalidKeySpecException e) { Assert.fail("invalid key spec: " + e.getMessage()); } System.out.println("private key: " + Base64.byteArrayToBase64(((Key) privateKey).getEncoded())); X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKeyEncoded); keyFactory = new ECKeyFactorySpi(); PublicKey publicKey = null; try { publicKey = keyFactory.engineGeneratePublic(x509KeySpec); } catch (InvalidKeySpecException e) { Assert.fail("invalid key spec: " + e.getMessage()); } System.out.println("public key: " + Base64.byteArrayToBase64(((Key) publicKey).getEncoded())); encryptAndDecrypt(message, privateKey, publicKey); }   13120983870 private key: MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQg9ye6MPlsZbIKD3hwqWebMOkmcKHlk0NEmTbPKQDZxe2gCgYIKoZIzj0DAQehRANCAARZXl/Wn+3uVSyk/VDncYFNazAjPMEBXEwS/iWy0hwidaU3t3OrYXVMsE5xqx7qtgmBu0/dbCdyUmwMVL5CclFq public key: MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWV5f1p/t7lUspP1Q53GBTWswIzzBAVxMEv4lstIcInWlN7dzq2F1TLBOcase6rYJgbtP3WwnclJsDFS+QnJRag== encryption: BLcrguLmGY9Hetf7UmtAyTg+8fVmH2Ya/oBjRHzwkbTZpiKbOBR+a44y2PJROBZDFBDZJTExb17HqRe1XFxeDSA5mmb2t1xhwxwd4PgckThbGhLewx151Mww2eyA9gWDMC9Wqrs= decryption: 13120983870, base64:MTMxMjA5ODM4NzA=     package org.spongycastle.jcajce.provider.asymmetric.ec; import java.security.PrivateKey; import java.security.PublicKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.KeySpec; import org.spongycastle.jce.provider.BouncyCastleProvider; public class ECKeyFactorySpi extends org.spongycastle.jcajce.provider.asymmetric.ec.KeyFactorySpi { public ECKeyFactorySpi() { super("EC", BouncyCastleProvider.CONFIGURATION); } public PrivateKey engineGeneratePrivate( KeySpec keySpec) throws InvalidKeySpecException { return super.engineGeneratePrivate(keySpec); } public PublicKey engineGeneratePublic( KeySpec keySpec) throws InvalidKeySpecException { return super.engineGeneratePublic(keySpec); } }      

已有 0 人发表留言,猛击->>这里<<-参与讨论


ITeye推荐



]]>
Fri, 18 Jan 2019 02:37:04 +0800 https://lobin.iteye.com/blog/2436751 https://lobin.iteye.com/blog/2436751
ITeye Java编程 Spring框架 Ajax技术 agile敏捷软件开发 ruby on rails实践 - ITeye做最棒的软件开发交流社区 - 乐虎国际|授权平台   import base64.Base64; import org.junit.BeforeClass; import org.spongycastle.crypto.AsymmetricCipherKeyPair; import org.spongycastle.crypto.params.AsymmetricKeyParameter; import org.spongycastle.pqc.crypto.rainbow.*; import java.security.SecureRandom; public class RainbowTest { private static AsymmetricKeyParameter privateKey = null; private static AsymmetricKeyParameter publicKey = null; @BeforeClass public static void init() { RainbowKeyPairGenerator keyPairGenerator = new RainbowKeyPairGenerator(); RainbowKeyGenerationParameters rbKGParams = new RainbowKeyGenerationParameters(new SecureRandom(), new RainbowParameters()); keyPairGenerator.initialize(rbKGParams); AsymmetricCipherKeyPair keyPair = keyPairGenerator.genKeyPair(); privateKey = keyPair.getPrivate(); RainbowPrivateKeyParameters privKey = (RainbowPrivateKeyParameters) privateKey; publicKey = keyPair.getPublic(); RainbowPublicKeyParameters pubKey = (RainbowPublicKeyParameters) publicKey; } @org.junit.Test public void test() { String message = "13120983870"; RainbowSigner rainbow = new RainbowSigner(); rainbow.init(true, privateKey); byte[] signature = rainbow.generateSignature(message.getBytes()); System.out.println("message=" + message + ";signature=base64:" + Base64.byteArrayToBase64(signature)); rainbow.init(false, publicKey); boolean result = rainbow.verifySignature(message.getBytes(), signature); System.out.println(result); result = rainbow.verifySignature("13120983871".getBytes(), signature); System.out.println(result); } }   message=13120983870;signature=base64:SuIF/kR6Wuo6dxe/Uqi3he0ad9G/ezsAim/9OsytQUHV true false   Java 标准api方式: 1、java的KeyPairGenerator,PrivateKey,PublicKey接口 2、java的Provider,KeyFactory,Signature接口   生成公钥和私钥:BCRainbowPrivateKey,BCRainbowPublicKey,他们分别实现了java的PrivateKey,PublicKey接口,并且私钥ASN.1编码(规范),编码按照PKCS#8标准,公钥ASN.1编码(规范),编码按照X.509标准。见#getEncoded方法实现。   参考文章:https://lobin.iteye.com/blog/2436665   通过这种方式,可以方便的管理秘钥(公钥,私钥), 以及分发公钥。   private static BCRainbowPrivateKey privateKey1 = null; private static BCRainbowPublicKey publicKey1 = null;   @BeforeClass public static void init() { init1(); }   private static void init1() { RainbowKeyPairGeneratorSpi keyPairGenerator1 = new RainbowKeyPairGeneratorSpi(); keyPairGenerator1.initialize(1024, new SecureRandom()); KeyPair keyPair1 = keyPairGenerator1.generateKeyPair(); privateKey1 = (BCRainbowPrivateKey) keyPair1.getPrivate(); publicKey1 = (BCRainbowPublicKey) keyPair1.getPublic(); byte[] privateKeyEncoded1 = privateKey1.getEncoded(); byte[] publicKeyEncoded1 = publicKey1.getEncoded(); System.out.println("private key: " + Base64.byteArrayToBase64(privateKeyEncoded1)); System.out.println("public key: " + Base64.byteArrayToBase64(publicKeyEncoded1)); }   公钥和私钥的生成也采用Java 标准api方式:KeyPairGenerator   private static void init2() { provider = new BouncyCastlePQCProvider(); KeyPairGenerator keyPairGenerator = null; try { keyPairGenerator = KeyPairGenerator.getInstance("Rainbow", provider); // sun.security.rsa.RSAKeyPairGenerator } catch (NoSuchAlgorithmException e) { Assert.fail("no such algorithm: " + e.getMessage()); } keyPairGenerator.initialize(1024, new SecureRandom()); KeyPair keyPair1 = keyPairGenerator.generateKeyPair(); privateKey1 = (BCRainbowPrivateKey) keyPair1.getPrivate(); publicKey1 = (BCRainbowPublicKey) keyPair1.getPublic(); byte[] privateKeyEncoded1 = privateKey1.getEncoded(); byte[] publicKeyEncoded1 = publicKey1.getEncoded(); System.out.println("private key: " + Base64.byteArrayToBase64(privateKeyEncoded1)); System.out.println("public key: " + Base64.byteArrayToBase64(publicKeyEncoded1)); }     @org.junit.Test public void test2() { String message = "13120983870"; RainbowSigner rainbow = new RainbowSigner(); RainbowPrivateKeyParameters privKey = new RainbowPrivateKeyParameters(privateKey1.getInvA1(), privateKey1.getB1(), privateKey1.getInvA2(), privateKey1.getB2(), privateKey1.getVi(), privateKey1.getLayers()); rainbow.init(true, privKey); byte[] signature = rainbow.generateSignature(message.getBytes()); System.out.println("message=" + message + ";signature=base64:" + Base64.byteArrayToBase64(signature)); RainbowPublicKeyParameters pubKey = new RainbowPublicKeyParameters(publicKey1.getDocLength(), publicKey1.getCoeffQuadratic(), publicKey1.getCoeffSingular(), publicKey1.getCoeffScalar()); rainbow.init(false, pubKey); boolean result = rainbow.verifySignature(message.getBytes(), signature); System.out.println(result); result = rainbow.verifySignature("13120983871".getBytes(), signature); System.out.println(result); }   private key: MII81AIBADARBg0rBgEEAcBtAwEDBQMCBQAEgjy6MII8tgIBATCCAw8EG/vXPChJAFWSY0EXdevAjQifNJk8mlJg9EDleQQbwOKi8ltFCSPJcpX30diJip3b0A0ifK4c0C+KBBvGGTj2xBYv5CW4kWHdA9C0o5tP+Ln1ZDA/MHIEGzNTvxm8jY1Mn2oMC4Utt6rF75pY1DtMMvLHTwQbIWnB1Dgz/U1KdhrN7izntqFR1sv1P2SCsJh2BBslfbHlHcETxQteLuwYaq46NjZCvam+NjCQ81kEG40eKM1Xtc0YBHSBwCE/w5f4I5ZuoG1puDlFcwQbeN6q83s7kyxIoLMgnKVYJzUW8sLYT6CiSIEiBBsrkVyEXcXXx1S/wsLpye5frhHXkIg5BctKPykEG/xW0i4+pnKrroMOG1W7vHC1HGCuCC293KUsWgQbhxiZoGRqEremfDskhdbgJzxGLUYvyQqlfXJxBBtZeHkDvh37ybLfQlv10zkWj4igzyKyJPv2ntMEG5liqmpyVzW6V5+hg+OIA4xG+Ty48byvKWYExgQbVPBMBmYaLunun1BSMWFwaT7nFsxEsvGU/+eABBtRgRZ1shPy1iNmKkfyHzDSJFMbcEHuedidGLcEG03dTblwcbfxvYbDMBQr3wGP1n/RwdRVcYuCLQQbe4y4C9TnU/olr1jSWMRFlsSxTnA6/JUKOLl9BBsGtoVKJYdVSMciDk6HUjmOkvQAtfbyvDPV2b4EGzXkwG7THgCiELEksMvaQtxtL5qcUUUaPhLL/gQbRoedoq8bv2d497djFZ/3l5I7ujOOB8T5ZBqgBBtvl11A1w/LeUjDoKDv/8th7qOiQWPYNcn2wX0EG9Pd4NY5wzgh1ZHCAILi335Vloa35wjOS0mjGQQbsBs4I7p+CFnfkiy5MnBLkY7DBdRvyTE9z92vBBte4hLukLAGHXSJA+kG0d6wFyRzDLgEPcOjE2UEG9HG5SvJEp/x1KVKOVpBmnGc+2K/TZC31+XPXgQbGOCtp5gf4ZIK0WUbQuo4RzYEbbS5VOESVZ4mBBtrPLyP8wqpuzgi7xkjkd1kNFXWVcptWy/IN4IwHQQbDRWh67QM+8FiK+p5kdv4zTuMrXmZTVJF5eAnMIIEgwQh/I9NBcM3LVS6AEDuIXIMb7xT2o/kz3qj6RaKWu9MZKVjBCEZBfuIL609gCzUsVnXWMrlaZrFSVAC2s5+Fp4AdST84QIEIZxesQln6o60e1R6JGdUxdDiMDf8cHEDp9r0kr319uW6OAQh39XDeHD6dmvJr4gGW5FNTMMM3aPvZataBW3dsgWEZoNTBCFzFBRcWzX1YkDWAZ4F87IPYX2XumHH8njAKpO3WX0sjTAEIafMtSaI2JAxYYArkN/kTjJe7WDI9y/mxLvVCbMfG3R+kgQhx3EYHTI7Q26SJ4x0h+aqCNR/ojeinxjDX8NMgY3Ygam+BCHHPwqddNk/3SR/IeBkFtb2VG2KaMDYfkfYl7V7Od+6Ox0EISB91XLyzQIUpovKP8YF1xrbHQSV8Fs7IcpRUMeZ89yKLgQhAkkb/4QmeOOuZ0rd5FBkg+RZahgly+IdeNys8Hrdq7N6BCF5PSDooK2iDwOLtvnBFztXvnGm8AUwecIq8c5PM9ULfYQEIXRnOuoYS+iJb7fNustBQ3QgDVFDE9Bk9F+Qt8Del7c+7QQhUuLDBPW4V7EUdUZnPFzcg8dxhTR7qumSCY1FXuoGstMQBCEKjv3mdUVaGxKDIyo4V9Lh3gi1o8LwwiK+Q92rTYPMpVQEIepbM/AalPi8fQcbnqsi4vSQLQ+DT1YF4eHkY26S/SUwkQQhMCi5KCLz9dlUQlFMwETYG4kzXtFN2/lWuX4S+Et6BuimBCH6+1QXUffeyA45opIXtmQwIVNtmMcXDkcV11ekrtP1wdgEIU2b5ANgbDXQHM7pgTrCyfWGC/Yrk92cyYd0hmLXFpTmsQQhO7E0bOAK2ubbdu6EyLAuulucyfdqwxs402xzYQGqcfkXBCEV9BBJBm1bl+VJQ9cqqnV894aIeIQgRHD3wFeAeHrygVoEIbrNqGX8lA5aeuFdmLXagx0a8TuRtjdMyjcJW/XYgkC4MAQhbPtu1VL8rJL8iiCKHHQQjfTQOan8jgxuIdtUqt+I/NwTBCEnnssq3n5c+x2/zmrQcylDDAIsZE3vuQFfmUamFrUcUlsEIQ6M6bhJQd3CSlax5NNS4VQ/Ef2QVsMlPI41q+Cw2gDPmAQhA3vs1T7IeLmL4FszrRBClVc2U8mmXk67ICRTmUsIS8N/BCETk8qM/M6TMp19eLI6V3d/hTYGJ1Xv1brISyF0UFs2ZnkEIcp+2uuJE7cCBn6VLThGX/aVKtRqm3R9kiYgC68kyHUUGwQhMDRP/i4gC+bku5E1Pi7lPY+M/3bE+Hrpwqhwqurml19xBCEsynDxao38ZbjAB2hppc0u8h8qPGszCpxQ0Iu+xqu6mToEIWFHgn9GASbqR4e677e6sNHB1HGYKvOKXbJw5aToq/J3gAQh+/JrAMPzZFyjEG083r+XEX+G8ZORAERoLRw6AbIhZxSgBCGgPI3X25gFnmsq07lVmTPcqkVIK9x0w5pDaNhjnudMwxgEIUy9uTujk/rMbFaPS70e+kszzJPglX+KWIY0NMufNc/SsDAjBCGp7b5z+ClfZrKLk/OJlnROQ/ymJWgH3k+SfvgX7BI9saUwBwQFBgwRFiEwgjTIMIICvjCCASwwMAQGNI+bq3PxBAYYXgX5VuYEBnUI47uTzAQGeeOcUr/BBAYxkcl89bQEBvJ9ZOJu5DAwBAa96a0nS/EEBixBsYLmDAQGiftOhTHFBAahPWpv6TAEBtHBFmmhUQQGJwBoCiq0MDAEBj16GVppVAQGQ8caj8hJBAayzMRuvcgEBmowHas7ZwQGOFSFiJfaBAb20Wlv9zUwMAQGdLVl454gBAZjKQ21bXYEBv10DKduwQQGRMccYNrgBAbJzIZBBqUEBuEhiQWTSzAwBAYP068aQscEBrxKqBpqqgQGaUWXAWD6BAZ7TrF2MbwEBqzaNgZkRQQGw3OTFhXzMDAEBsqcma5l1AQGSlZl7UIJBAbi18b8RnEEBsYfzHSgXgQGVLIJbD4BBAYocA1QgDMwggEsMDAEBlWdQZ+ukQQGCTeR6jlEBAYeJbPZ1tEEBge89/UFWwQGwdR7C68wBAbjM+3WqNEwMAQG65aIH/dpBAY7dXJ+vbsEBiWNRcHPrgQGVqmY+aq2BAYSpQvXx4MEBpYZJ6XFwDAwBAbrutGpKYoEBuoGS0wS9QQGFIkPlfB+BAYzR9fP8sMEBq9/zDYM8gQGBuuakyxaMDAEBm86LHh0NgQGndFKBb6kBAYDjG3PuP8EBrqXh3J//AQGXR3lKRsnBAZFplZbfSwwMAQGYlna8nGJBAaNce/0ZqYEBrA7w5bg1wQGF6bXF5rmBAaShrK6sIoEBtbf4dRx2TAwBAagEc7N+ecEBkZT2jZ2qwQGFv0xfyMhBAbOLaTBTMQEBq18Dv1GaAQG592Ny209MFQEDL5WC6DGl07usSGlBQQMhFXKrzY8cK9y/6ZsBAxCjno/FXU6yYzZqi4EDFknvoSzFzR4ZnFI8gQM9SL/uAR1oq+eMocbBAxdgb2f6v89WgM0N00EBrf/wnLsfjCCBS8wggFoMEYEDIG3hQG3K4EQHTQhhgQMiSuF6WO+iYs5PyLTBAwFihXRcsHZepVNwr0EDKBu51C8U0dVJzSViwQMm7+4FadvXVaA7EyBMEYEDPjkF33IJqqi5unj9AQMcD4MrihHE0qNz5sdBAz0R+QeUjeP+HkFb7wEDGM+C3+qBFRbt7dS1wQMjP+d3yrsacLX8+FQMEYEDLmVA/zLFZK7Ik0uFQQM/lyUWa6tv/iwQeWBBAwPvuG5L93XKMKwVs0EDH/AFMSz0CySviLXSAQMfUyYgIwc7DJ4DrgaMEYEDFLM7QT3qo4OPEND6wQMVJHMdLPkvgS8PIdGBAxcaMvN033mG5tpj8QEDC6A2gwtM756nHP4UAQMVI+aeFEs0zp7x6aSMEYEDDtU5xttPkVBYRrbGgQMIo/345zXK1W2smldBAyZW7EnoVFdj32JglsEDCVh30y17nKKL6EXsgQMUlvZQoUuc2AgB7buMIIDVzCBqAQMyH8VQ/d+NVb/UafvBAxFsbDIbjC/hEkz2BMEDO9qZsosantc/fSp5wQMNc/0b5n+q6yP5WYQBAztQb6qzlNN+OpPSyIEDHpy982dQeHwb8e4xAQMICfjUe/WB5zGy/x5BAz9tLywvaBh0rEv/HIEDKOxUJo0DGqFxtqRvwQM8Pucss5yWpxsrXfbBAwJNSaKlQqkxwdYdNsEDL3gOCvIWVPXoinxdDCBqAQMCybn2LKY5W5CoIXDBAwwardaLgvmTZsrnLEEDLesn3sKIY9Z2DK+VQQMUUYIjNfu3HEV60dlBAw2hcED9EpBjbVvgnEEDK3PoGnOlKucW02pTgQMr+elfqgPPJxo6JxOBAxT8OQy8mRkLRK2NVIEDOJmRUNRPjWTf1I/ywQM0OBRd5H7uXyQfCXgBAziy5VHdb+8ZoHh+tUEDH3X++xO0WhCiTc5bzCBqAQMytojxFe2tvMkIhnQBAyzg8LkqKT6OMq1mNgEDEfsfmp5QzJVXkvqiAQMyw+7nTpIAK0Xys+qBAyTM/s06pw5E0x3+t4EDFc8jvGGh6CwnM4HpQQMlLPO5miFANjtR0JpBAzXmgLoTiMQgYJC0bQEDB2LnctDwDYLz9EsUgQMsUExqXJbsz+p9eUYBAygoyeB2KxLGcmBaEAEDFh85Dh6OWMFGAmoEDCBqAQM40sNtOwbjoESNHYhBAz1YRWHW+KKsCBmCdIEDHmGAuN34RkvRWtlRwQMk+7d6RcLk1kMA4gKBAzIvjBujeQ05SrAUaQEDK4eAiT++xdcfJrtMgQMy4DilNAHCWJktK94BAyTDG6DVZxmpzfXCcQEDNGVQ3GWPYLWDFHjkAQM9eaIBRlnVWvTjv4wBAx+3jGtI0WD/OBKzkYEDCqjXsDNOCJNnUamzjCBqAQM1EhV5ZqZt3e4RceTBAxXmWXupvphhpX2nf4EDMOtPw5ZYHFukE/kegQMJUFHN/KsmEwTQP+QBAyZY90MzLo6CzhgesoEDE6C4W6eCu9M0qK50wQM9NmXOyW0dSK2uAwPBAyJ3NsfxYT80wLGTYAEDF8o0kD8xBKSC5sXBQQMoTMi/WLs4jwIikEIBAzXEEq7v9BCWS91gYIEDB9m23gq7QYsxvs1jTBfBBEMoaKVNPGFAxnzOrU54kgBgQQRd4a2YI4PsjbMLzueq+ts18IEEU7plsYRaDIB6fVkxAchy1i0BBFO2GupoEx+pdbh/1Cj+3vrKAQRM1JSqKaH0kf08YwpNVxMnNUEBTS3Qk3OMIII0TCCAeUwXwQRbnEePvfzSmAlkP5fQZwwlckEEXW2oiEsIDxOIyez1iXxzKlbBBH3fPQkbwV7fNQFNc4UaTlowQQRq+W1ZmWT5MJMjQXH/yQNtnEEEap9n8qQtsPyaOpnbCjTkfvaMF8EEcFOnBA6lHVG4E6CJq0IyHkHBBFSu9W45AKRyKX/dt5Fe9bAPAQRIUBz7EkEUx3wguMXJRa9FwoEEZTkZY+PpD3Xgn2eXx34qzZbBBFOfZjOIfO3y9TI0HAt7ByDgTBfBBHl7GkymXF0WalKHZW9euXbIAQRpey24J0qATQEJE6AyA4JdaAEEVKUgF9j3f5r6MG8rfEyYCcABBFwY4R9j68jXX99Hm3IM3skbgQRQ9KYhi1tYOczr/CAgI7uRYIwXwQR9CJC/P6KiavngHepHpaE6PUEEb8T+zhGcmGC/0Bd0JeEiCmOBBGQAn6AzIdHi8/EN12MwmNdEwQRHjXbDgIga07jXtqnR1byo1gEEQKgiR4LLD9NdKssr6C3FREVMF8EEROcCjIebc9GP4Fw4Qm0NUg/BBHIe0NeHTkJwIPnFbCNRD3ONgQR1lSd7B9f/BtcUMjrAisKbFYEEYZZooB5nVUd5kERxbH1JsQpBBE+9zjZLRXbYuwq/BiDkbOCXzCCBmMwggFDBBGjfT1nukm+RxJlFOgNfBogewQR3tvkjaOpHJ031TYEXvVgZ4sEEc8unJz7zJkbszmr0kdgJrLwBBEGjGWU9LJmrc15/vc3d5sEnQQRcJ8NyM5LS02UEqz+yRL26oQEEbK3TuvuztoMiE6Pd1v5JOwoBBEMFPeTE7NC8tH569mkBm36JgQR7HI1ZBiNqLtoCDqs8hR0GS4EEZC0aTtHEBzNnYu2iu7388rrBBHnmjHw/OUTz+vTqxMj46JesAQRgPooA5eIEFQrFz6I3fW4hyUEEZsLsIUBFEsHBCSfwzdHOLhQBBEHNxMjFZpgjPtFUEt7Ro5iuwQRVy0Q4Sb52T5ZvmEfJSW0GqUEEUSxNy+EP3YZrHN9MbHFUoJVBBEcfBShChgzOinx8Fbw1koo0QQRgz7cNU0HMlns5kjbdQSlY9IwggFDBBFbHGzO4JZFhDoGPbx5lpO+bQQRQeGq97VvVuwQ3zni1d9b5n4EEeeWKW4hAWHkG5NEcctABn6hBBG7XI4je1h05bQAKChfg71wcQQRVBcZbcTh1lphEO12DJ9iq1kEESJdX0r3n7Uet6ZeOMlr5fNEBBFx8tI2ML3ZsPzq8NEG+SfHXQQRbBeTHLrfdEp5Mqt8tbAwrmQEEaA0ZTdsfvZWTLtrxuRzYSJkBBHfpbPMm0q2xy7617thRN491gQR+KzYGH78KkHW0kiqaRrBUQ8EEeK5Rdwm5NiVkkTO/JGUmHSEBBGber285Nd7DhGamItcqS28UAQRHs2s/+pM5jSpad+9x+9VFWUEEb73bQS4ZiwOYIjF5L+tvSpNBBEiqbMEfcK3uuHY3iHLU71K6QQRISFP52tckXQB9+8JZVMsSoUwggFDBBFVhn82g+20BYYxYwXeDSufpAQRurJfhJejD2f25xN3Um4SLkQEEUA7F671BPWyZQaJg+KEM7ukBBECmRWT7Jd4B8/K6AuRhn6e/wQR5JJVj9U0Wu6z1NNir1u2J0gEESA/2BE/c7vnN4dchueh40/ZBBEAYe1orlJy9c8esOVU5zxmswQRvdZCCkHHBWTdJkK4FFvfF8EEEX6yMDa9XHVbxfTVUFqFBmOfBBHLrIWN12wMruZz66nmOYG1swQR9dGT4I47bGW0DrNF1v8A6yQEEXA9qZEATz0rGHAXAYLxuEgqBBGUWrP8kkrZqKHTb6F+oOsT8gQRq2MwAfX9WaOmraKLzpvF7zgEERmR2VnS4u4OPQm6cz7Wvod6BBGuTA3u3yc+BHrFZEgXNhRA5AQRoHXvH7Q5jP4veDH7BTxhX6swggFDBBGMyov0eqiJaT9mdY77yplsRQQRJYl7Ye6hE5uwe8g20hu7evEEERpS0JnpzPnhJJFow60nggVYBBGtXuVj42nP8hAgCvUnEn1zlQQR6JXXXnyr9K1lQoVCvDnw7fwEEdFlcRmJqafiM3PGz7EI/Rv+BBETGWG6t/ATFJ1+uopgt2D7HgQR2KWeKtLj6nO0AC76zK0Zw7sEEY7ay/xpYCb2Z17VF4Nxj8xUBBEspHMG9+7k9lnXMdXGE5kd9QQRuAfTLKolOb8nl67vr8W94LIEEVJlkYQGDI1t7oeI2xtSBqtpBBFrOZuSDGtWWwHPXwK3vR9EuQQR1oFr+l9oEtSvL+CN7IC4rFQEEVdFEzFvdsslXM9iNZDcVH/TBBH7+umvkNkD6Tn9hVGE+iR9TgQR/yCdZW3U5len/avirrQEXmEwggFDBBF0jYH7bzDV2yuxacQUhcoRvwQRnNpjUyyAIjLL+YBLQ62aRhUEEWrF6jqLPAqP7TtrYABm1zypBBEjStmgi1ZUDGVaPCTVcaGQzAQRET6PJujtmkWMsL12xHs0Z2IEEfaUouPd7r3G1UsGnRZNsuK9BBEoqtiayABYGM9DPkYgeLL+1AQR/J6/k417tzvSbxBgLKNToHwEEQxGiN1tdL/xM9d/NjXIbSUIBBFrzGOdDhjjbLdifg0/EXzBeAQR413HpgH5D//TkDp0w26s/b0EEcLS1fkz9+gu7xu5UuzYyX12BBGGsz+087DZzQdsQzO8/zbhFQQR4rYmdohv3psRJmZEp2tfdwQEEU256BK5S3CwLJX0WkZm15lZBBHtQh2Zrv1pVYlkxzq6BsgQBgQRkjy3z0AyQ/5zpItwnc43LVsweAQWzHZ8MOGN89kKDWz6bEecB/wT6SM2VgQWOnkRkE4ODE5WDcT/BszZujUEMp47YwQW6awVOmYWA3SEHu7SOBg5pFpq4h349gQWrdRYauzwRfVi80HfRR+mbTPFwfZGCAQWF8g9spZuN1psQ/e1UocUd/8+kXSV8gQFme9Y2JowgiP6MIILhDCCAQgEFsOEHGeoEaRhUiolrDK1//7N2w6gP5kEFsQ4D3F4T9/c5+mj/m2OxA+oj+cNyYUEFmr2uomNe5xJuQK7wo14alLs30h5NyMEFhyu/mgaoGhstHpYyejISp7K4ajsmaAEFkDkoCSG5K+gvbS6ry6pzvYq83DjRV0EFrcdW4SKNU/5IXZPZIe0Hbw2emlB6k8EFj8wBfweEL/GX8j2xz6xGv/0zARXfi8EFo+Mdzf37Jjo19AcTtbrTBqy1v25yeEEFggBPHWUth73FAnbxQCDtjGoYw3lQU4EFqKur+JkwzQPdT2nWw0Vib4bDHtqDPAEFnit55aUpwEMCkCMFxLTIeBYMWgr02UwggEIBBaWhz8ryOdn0bk7jwaVeG9xyR3qhviuBBYczMLqYm6O5swQ4AtfslHv7ZhqVy46BBbh5VRQ1U8KzqbAvaH59wW1H1lgDqXlBBYs5KNZHzCy/czjHnFluj40Dhig/vA3BBbyckdoNFlX68alCMCuHxwSDerZQLwxBBaBktPdJZ1RN6nZeE5Uw6ehDdMi3uwVBBacP5h352EHuLVQekFifQX4uY5GrZaUBBbQEPNVk9nl1sAtv05AMvdn1/YCvCJNBBZ16TTC+OcMHFSJWRtjfrRRKnrMF/ubBBZNDZg6nSgsGhuaLPYo1BqOOJnX7VmjBBaG2nLuf5AE1CYBmYHGk0Savs5tE5bQMIIBCAQW577kRJKm2M/XOtZGa3X0FFavmsIiHQQW0GBP4EwfmQtIpmS6OeJgr1Gt9CEJwQQWeUj5VahFN9yoBxxBr7978ED+3Eb16wQWh9ia7n5PtEXqFMPZCKTHO/prYhV55AQWyqzqZUycq9lmUj66YUIFZCEhjGx6JAQWvM1L/t4GP3h2rgB8WxvGgwwUsOoShAQW532fHZd8JzU5iGmSxJc153czXqOnkQQWCm95zKktbc+ebyFi57CSr7fjhsRNUQQWi3W3Vn5Lvgxqruz8x1H1AovF0PHpJgQWhV0qklo4sFhNd8ZVJU72ncZpjC/GnwQWpvoDvT3iC0viQxqJOrpUrW1/2GbFjDCCAQgEFo+/mElBgUj7cz4OaqShv3cv5Pgwv+QEFgmzVPHxx3vk1geH+h6B9iwG/XeoGdIEFkgP2mxKNpzOpOin2yosoEwYOxZjJyEEFp/qP+M8ekE8ZveLblVj2qHp5C44RgYEFkbM+vUptmzqlLICXUkJ8qwfnQqSGpQEFpoAYSlemIYd9UpMtb0cPZSw9QfDLD8EFtALxpcv3M1cIYYRLfqvRdsvuoc2ztYEFje3F6rct+g+o+u9dtjqcxGHJcASVjoEFr5wuVsaOQrzUS3VYZfZCkp7Qa2PB/8EFlUqXctJ/dWSlv3S1cOGYrQp7BoZNI8EFkIlQ5OJZ8OpSlWYWCE23/Ijh+/r2rgwggEIBBaZXWG9VAULrKjOpr0kxWoHe4wPUnKGBBZ8qOHQMwfz2Ga5W1pDPVs0/UrXEyJ2BBZ7Hf//0jg4GzPPq8MnQ9ZULgOTj5BqBBZ5a+kUdjNp17CnGmVI2ZssEUJ6JgvABBb8jgU4aAgIiHjM9TEnLRLvPcibWUhXBBb0YsU/JCR3s8wRcmpsOK9IpgveFf9UBBalIkbl8x6GvhkxSZt4wQZzfEnJEH8LBBbTthW716W5EG+L/OXs5RlPYiN9mgvoBBYaPSQrUkk0LdwTyeuCPF3sM7gUdlcyBBY5sA75yZFhRDrrwLDrQbT9id6Jo//SBBZFGKmvo8X4nCeihhDoM/9bYHiOfGn2MIIBCAQWyq/SVTagdmq6WsMyiRqlCJwspAK2egQWVAXqvnmJA5jnmz+BJBS9GkE5lAO/0AQWWy/Y1t8J1zfGPOfDOi/HxcfoqQiivAQWMEFKbkUEIeoP+wBxaUF8fODePxUYDgQWmrzrdOgBWaWhLA5RuNFEkqdQgiX0/wQW6mTto4s/pFq+1U2/aEJ9Q/o2KlHeZwQWA1yTMGQDqq9ySnKw2QD9KGDn3HWHiAQWZZ1Re9oK2XZRBfOVVniVz/TLAbUCQgQWpS5RSdw+CeVru0owtHk706eFRNcNOAQWwriRt+gKN8XCfy0e/hcyLecu92KKNQQWMFkwUXtXeTbjAoBlnRxZPg3/wj2F3zCCAQgEFrLeRdHZnbiv5jMkt2IidGDOHEYZvOsEFiVqVjHsObnbo5Rw8Vvhj1m88SgxLY8EFqY0M4JUvX4LMuqFALLVEKyxQIUwu8wEFmt7TnoyD1CRXUO7phFC3gz5+e8r2KsEFvN9hV//OBbZ452q5YRGk2vQqBU7RTkEFltqm0ghacep1fQCF1qaODRhnUL6BfYEFgl/8e3PjTVWVlWH64zaqs4yLU7y5KQEFrAHlpHpJKqsvw5vzQNuMD3i4eYTn8kEFnVAxqGkrbKr8gFa6B/5tuwC+2NqeU8EFjCxnZot8zD+hOa1hO4p8hMqcGT+F1cEFgccX0islVw0y0Teu17L723hjJfPjekwggEIBBZ/Xy398U+m57WEWxln92SDuD4nwssLBBb97JBStGLvffE/uJrYkC7o0eCfCGhjBBbsPeA3RizSpcGnkP7t0vmFjqZKq9/YBBbQGIrpM2fw/C4juYWjPT7XpXBCk5B8BBbIIBDpLS6//XKlLEj61UsPc7OhrErMBBapI/S6xbKyU4Id4mIvGyjwDhwMbU1lBBboM17NYM08t+PdvEHrDIgTFA9zDdWTBBZa4yXeBsrLlvECJR3x9ktKArdc0fNnBBZj9AGvaGDSBAS+oqAUks7c90R238gYBBZheGKa294ge4e5+mpwVdCoc9uMUTyPBBYVrq3D0G14i3AA0BZo1dZHRq6ImuG1MIIBCAQWEbirc0VNRq52rfQHvUaWNs1NZxfeggQWWbO3zzafgM47b0XaTR6z271w4h2dcgQWW1fwAocShx1w0Ioj95PUlU71nuZiEwQW1K3APNZcSxxCSXjQBU7J/jLo4CaVAwQWtnb4bYebmpWN0Jlpj7np1Yjl0vxr8AQW0mhpTSjm+sEtRMILPRoJC8bY8LQ6hwQWsjdHujRS4rxONysiIAMSXTXnpWJ9PgQWJit6r3M9JwGkf/MkOGFi5TMZI/QuJQQWFq6pvDkRTn+O4Il9AFhCjVbjcl9ejgQWZSSwlrwqxAmRhdiPfh4anLl67OREXwQWoKNwK5m2TSYKT+aZdYZkwUPZ9gpuEzCCAQgEFhiCXTSgltqfrQNE7rE8KVNimAvYAiAEFmopLNeAIqCK33nOQAaCrr4NO1ENxusEFrPF1rnZ04jFq3AmSzqpkL5pOX9j42cEFqIb38kfVDT8dvQzaFxULZSZsk95lJ4EFrauawpFCIhzY3Nd5Nl5lhtGnkIDDh8EFu741u1a/ejgS7fNfYcnV3IHrwD8ImkEFqLPSrP+OeEme8URIdVt6usTygLdAz8EFpG4iMeletbSqr/Ls7zNt5M2scr0fSYEFgVyUMakInfi96/lHAN6/dL+L/Bvu3YEFj7gv7PNrJdma6mflllWZ8NjlqIcfeoEFhwM1Bou298HUbpsK7yNGSfrVQY1zGowggEIBBb+gtSKR3XMTHFZ9SzefhybkUar9LnnBBZeNb6yALiHNmSuc2XXx7QFcoRWrEBmBBaa0NAZ8PQVJ26YTOGDJoh5pgrpcjrYBBYsDOFlY/pX4xb/ZnFYIwJauJ1nME+CBBZD62uV0UAvh9hsXSMF3RomhDCmZKXTBBYfe009+1GLV82DqPmqXMbLyMyHAXxzBBaPAw8DU0E+GbzzW0rPPIeFFvA/T1F+BBZtknMFJjbFkZ0Sz+lZ2KbiBNnNOYT1BBYfcXr7U9MIdCDLP+PVkDgSowS8T+RDBBbxfxX6RwIC44xrkGCFTfMo/UfqvVH4BBZ1T5YS/Y17d83lD27aRt/vB+Vp6AUoMIIW3DCCAhAEFhdL2J6U9fWjSlEeBaVOuqjoZHt4lBYEFvSF+JX8graO1QbvLysH0XtmG7n+RjsEFnKyFKb/BsPCYpZwZWI4S1Wau3YGYsAEFmRJAKk7D5Cs0w/WWevOAcVGGUFZtTMEFhfwGJtn/BEST3RPIYflWg07+Elc8rYEFm9npB7spemew1guYV7cI1sYltGfm8gEFmGuFJ+SVDQXxaB/PnYbxfZ5tuP8TXEEFk6liPSRqfJFMsJJLGqCL8OSMu4cTb0EFmXAQiWFMlzCySyRYNhn75Tp5C0NmzgEFr72xnX0tYv62eEwS3n7xyx8mz5MnssEFmZp0yhrhfxYuxdC6z780Rs+4x8op6MEFiXrQCsIj4mQtK0hp4RoU7IvgiXA6o8EFiE20IKQMdK3tAea+dzDKnZlRfhKiXMEFpA2O70Bz1fR+1s2Fa3xGbgdoGadT9kEFlisaROwgHy8ibOL1Iw86Ild+dSS9JcEFk1xpT6hcnJcg45U5akg+qLIqc2Uk5EEFopn0uEMNTiMokmZLjDN0GmPJr4MX6QEFgt0lOmkheN2pCfsgkFOqssmVyQtTEgEFmg+0bpxvTRF5/Geo1+3rf0dPyF7IEAEFuo1RxXuaBkRxJ9FWP4A9EjaOCn1064EFtp/FvKwxtHLEdaKQlH9Y+yXhzuVEOsEFiWi1/9Q+8BgCXIA/Yey21yB0HyEsLcwggIQBBYr7YQ/1pypocREwXXhYnYfAHXW5W/lBBZ45mxPgfjcwd558QkLObtAffMGExbWBBZbUEvmSc2zPg9dDBGMuy2f17iR3lU+BBaZbXa3fS3iKa9Zf4+LQa8q2xmEfPcBBBbe94ZJkr6XfY7ERI/FZU4YjeIvie24BBZ0HokVW/t2Cqjk7QiukbtNJkyaG5kZBBb2on9dAUB59Pg0oUNzRtVFz0MiU3Z1BBbueZqiax0Nzrv/ibqfcb5EOQufMS5hBBZQBZOUhBOMCbtfvpCxTEMT6Nb0WDyXBBaXoNdrslypJDSVNGJD9el0nlhc4/fNBBa6XrnEEpyiasdHY4YuVPlJ1TDsUF2GBBZRM8AmGGxr2DLfQUar+6OV9KjtJy1JBBaTFj9xU8EKrej8MO7n+jdOcd9/RmJ5BBbrm76N/f3xktZAwn98QOWGnhnwZBP/BBYeyx9bYpWf54s+Z0yLd18fgJ3XS5LjBBbIJ7FKIeSzNGuh9LovAkfC/ZUXXTCHBBagWmmEnkfiT3KsQLTAOPltOR3HullVBBb873L6KY/rvnTAx5pUvrCO7D4YBEEWBBbcE/o03VCgQtrBl58M+GTFaguhdvgCBBaL3Buj7o++JKXHWIT/lMGii15pxd7SBBa7H5BRkYITV6sfy1vNKhnTwr3x7UHwBBacs7MvX2nubLXKdQbNr2eEyuBID3ISMIICEAQWUB6+N5xCYxpZioWazKC7UCGATZjq/wQWiOO6PJV/UP8b+BAOVtq8U0BLoY4h3QQWvnPO4jE3wQtZxNoDxLyoJIpo6FqQuAQWKCOEBzZSSWd9xV3iZqrPVfebzfjU9gQW7t0DG2OJvNpw/z3W6afkeSHRgX1OjAQWp4lKVSZfdD3ylADgO2qtAVRXKITL6QQW9Nl1JsZ3eoYW4kgIMOe/25+CPyHjZgQWh6DGqgmEkvfsbFOM1OSlSuhNYN4MyQQWWtLU7EXcYXlUEQMNVAhUZajtR/uMAAQWxdUm8fZDI4NfcTohGVUgu8kRGurCWQQWxM2NbIyccZT6gPmwW2NUB92YHqLXIgQWS1seOPIzOLWR4GLVpEUIqW9QUdg7AgQWUgSpR1cTnsViUYipBl+yKFEK2TLEcgQWK377e4swFaXBhiUKI1EYLH6wgckaOwQWkEcITk5ss1nmGUIO7VhbahM3fL4prQQWfzbHvcIs9shj8FM8p+sN03mOpxDtTQQWA/jcxJAW624U6TxXvFIRk4OXfTkfjgQWQ2KTzSRcepNPJH/YEwZJ1gwj7+ov6AQWxMT+fB01khxGBblld1nmJG/XV+qLowQW7nOlkL/iIBJWsQ8RukhMIInF47jPQgQWgQFF+aJjITdiWNOA1g8SuKgfXt2DtgQWUPUoB3lV9mzRX96qochx8SPJ5mGxOzCCAhAEFngXAPJNWNRdBIR0cdN34Xm6Aj4R7C0EFjwmE3DDOT0TUOfHFQZfNXkItQhI8YsEFnrooVZPcjnqMv5uXOeor27vvVyg2cAEFtP8wSyoeDsMwv87ASTbKKgbLtIVMfIEFg4BXy0GCT6zVtqsCu+WxnBuzMDj8pgEFrAd/T6EngeXeeKs3UIfipRKsODBTqYEFqTsRU1Ybs7t50CV3Ujuv8MggUoDUJcEFrwr5Y4w8aqkzmizLkX6axOy3jG4TvMEFhiZ5nU/qrSjo0ifkf3Lz5YVZBrzpfkEFrITUZFje8MrdoEwuive7vljQq02TK4EFrNF7hV/ukLowotr2DIKmaW8gHAbkG4EFpsq+PaE29/KAd0pHPpTK3rmv3Z27A8EFjO3xkerIz4ggZdhHAHexL+axBj7WK0EFklICCvCF14oiXEMFBTPaY2oYm0pSVMEFpFfTRssIFod1uffWqLLVhHqBNWm/84EFjLgXsuRI7EIdYiFpiHHex6HmOjcEqwEFtrI2WYK89BTRv31Arz/fMLzv2XmejwEFrrxnuH6XejDCVOVpYlFuMaQ2c7wqx0EFm++3N1LLlJ43GT+ZO9r9IEgEZWdIkEEFloEQh3JVQXssnMBhZhfOekpC5kXNaMEFlbupK0wxmPgISN4TdFnc2dJYXnNefUEFgFezDez4v/HpntYVMRrQeI8O4GNPxswggIQBBZSbAF0bmbanVZZ+hvzMbUV5kuabzHEBBZtFwjJW9CrSy8ZZ/LpHPrQxJSf6GGSBBbBq/5u0pHloYyThv5HqFBeNw5845HcBBaGJL1zAKBGe9uZMNu6a1Tvhiq7xR3VBBYUpS3sYpdqti4wfREQsrNsFbAkSy4jBBYfvrXDgNH+pk/jhFY7wgnDGcHdajKNBBYGjufYwWBhOoHJgxSzPK/U/283MzoRBBbPuZ01p/HEuBo0h+0HdjhzglrbXGI/BBaeXh6AUu+CS8h57Fh5Ox3dkjo3BkslBBbBa0CYqH598tsdRyg6n4WVaZQ3FT9uBBYNmNF2V9RZaJSBSeEC+Q5Kt17l4nt9BBZ7jdsEzhmsJZuWj69v3I1Wp1BJdbahBBamWYkP1fLZkwLLvEA/ogkM6KdKI8O2BBbiU9CqogojxWMuhUQQDPdBf7hYuqemBBaGuqRIN1gU5L1KdEk6M0IoYjFGaTRLBBb6n1HRpoRNvxIW/ddwxGjKZjZ6ZGRBBBZBcruzi2i5PrcS36Nk6Z72mRHIEywtBBYQZ0COrTA6RTTu5DjHSwJpaKNiI5pwBBarl6nHU13lzdjypZ4AwxPu1EywC4nwBBZg7DfMEnCB4VJCidZN6XSS028td1hpBBazhYwZs75ArTPmsgV7OKIj1TE8XbXGBBbVWCtMQ462tgpML1Z0KYYSIqm1VYRXMIICEAQWvtK9ci7Rzkb5BfaJYzhTfrwhwG3NzgQWV+pb2safJzvJc/MVwpV9SMsRZwpkMgQW5iP1UXG3UeD/2fPf8yyJCEJkrTKM2gQWbtSiOw1oDOyvnMM1cN4UZYUbMxrMowQWctQKfPQEXkJqfA4psMEywlvctVCKCAQWLjCavQniWPSsMODaKIdja5b1AOHrbwQW2YHKyYHpqPxuuuyA4wOEKIS5ZqJUNQQWOb5SsSKjo0FCq2XDy5mdt+HSfS7yZQQWuGQj4NUaH5C77qeuhxoDiYAPFwlAuAQW6e4/YJh/MCROZujz0mTRBDTU0VWRiAQWYIXoMwSTbnzqnjK/0gppCYOcHSSuJQQWtMhzqRrS7OvTGs5GCAesjrE0u4DsmgQW0/TCE/EbpWccTyySaOIqtIWsZVzLXgQWi5VCilcxv8QNiBM0miaWvznn6tS8ZAQWxJF7qRaM8kuHNaVfIlkfBRFouJI9XAQW8BAFXz8B0IbUDDCv4VZitq5WtoFvkgQWRaqYJJwFGyDMxXIqCxL8EtmfPLQmrQQWRdfIFIq+FrUxp+t18hwS0EXb3WM54AQW6JJH303KSMBz9zKRtaiQiImB+h32hwQWeUESsKr5Y9Z+szhNiP5ofA8JsHOh2QQWe3xuzqMi+XcRcE4vHyXVtEAgPFXCeAQWGt51uMzS6/1UvHd9ycoHNLip/DgGOTCCAhAEFiMUwvtexJc3XPjdLGapketCKOMmecUEFs17BtN7VUkwxuY+5TOH98Nn6EGzHIQEFjzJDHa9RxRUNgllWxmy0pflt6a9y9IEFjkXaTBpbEzxu4veTKMOi7nYLc5JSMQEFjOoZgCf2tcS37oJG9yXoH9DtWOUetMEFj8Wmoxx4nxswAkUu7uXlubaN4xF3W4EFgFbUR9U/Gi5eDTAvBOwa+opNpJmsKEEFhX5+bc/Xxxw117t/k3uJlsQTeeo7IEEFpyj8ninntUtrYgH544q6+S2NececEkEFlcVSDTOFlaxWgFvQJ/vYtlmUe7NenUEFgz9AvqBeiordeyheOYNhPztDSGa9q0EFoEMECoIxclcQeiUHCyEbLvgYim/XcUEFucv9ohOZ1GYisXIVwTjT2Qd65+qot0EFm/ogwexOBummsWJ06Pay4bsRZ2QynEEFv5YnGi2D9RMyJJsUMN19Yx1myZwv1gEFl7fALFDZHpmz9gaskXcno69QIlo+OMEFl2RxjIzdeBUTMEoRTKyrR7bAmQRhRAEFoR+qZ129uNrFjO/L341exuXCeJdJzcEFq/AqgatBttLmTY9emTVSy/WBLp6pA4EFl0o7Y72UzXfH2mH1PKLXG3EOB3KYhwEFhZPaCXOi2jgi14Am4DLIwyVctyyOQYEFnqoL/3SWactunDyiR82zvhuC5TKu3wwggIQBBYVM7CbiDl9jn4zNhFdMSU2EcAGF/4LBBZb02c6innygRnx4/z2PmbKBkKYFQjYBBZlmDTvWvenu9Wt/ZXioCWoOhfasAGnBBYV51L9BQf9MJXCZm2zLW/uXN1InZI1BBbaYSH+fsQ7dtIwZ/cBloewnMv17CnTBBZhMuyCO1cr0aQIST8rQCu3yvaV1GtmBBZSh7+bmBZ3zDtBX9GtfYnn4A/B/FKjBBaIYJl7wI8b5jxPrHeU5bYG9/MFxpZuBBaTVYssXdrFrdxSTMCqapwDp+6DTBl1BBas3roL2c+wdxtDgov/yCP1wBDBefTPBBaIUoQx5ZJELJ9T/Ue306KMDJiSfPZOBBb3SqTQCnHHTX/bhP1OYvG0/AiFdVvDBBbEz48PlnOt6oXtVa0oTR59EJ735IHvBBYJ8uSlR68k9YPcdbMYdRXgRBqsiFlmBBZuFhNNdn6cpsPCXDjJaijsGPs2NHwYBBadwaejttFIo75Q+x6ra7bPt6T71O/0BBbo4Zd/0UuTtjNSnDTjTfBS8x9jiWtyBBat+VxVeYxv4sDrY8UvDlxgh47Z/97/BBa4Q6bEJTOHjsmF/XsIUqzd6/p15gltBBYcaXAfujwTj0UZtfmzCjvsgriWqJ1/BBbYa4GkyxC5q7zLnftFWs46rvrp3NP7BBZLnCSsNeESZ6LIdv4gjoZ0RPqFJGbTMIICEAQW7VMYOzUVOl5uUptVJIZcAuNZOKM9kwQWgf58fh5/U+IilaY1MVFipSa9J130XgQWzMkhPZvRetyhB+L7PNlFmUGkc1vtOgQWYgrevtXI7MKRDL7ro/3qKoGw6VobxQQW5tIRGjDOOpnPcVv5ShNuXkfvqbQU6QQWwrtb7Nco8sICo4jihM/HgkqapJPYCgQWuhYnzD+fm0gS4+yhK4QeN57Rn2vbswQWifAkHD7OErk2Jc4cfPfhHmONbLdtYQQWwOJn93KHfkvrfd20Ndos5wL3Zp03xQQWenCLELqk58nMLcru8Fuesj/Yf0gn9wQW78Jriz0AQn1McZynFcXeLLdZxd7tSQQWQuZ8yKkUPcMLsKc20045FwbRYfUERgQWfpSTu/zxFsi9opqCKnKzkgmHClz4BAQWX34YLwUceg/ADycNN6Ft1JlXvJJF0gQWU+y7GlBjwZr+gr2t8z345je9D2kYkwQWughy1S7DLlvXwJrjohiG1R4MC488zQQWsKaN3O0ir1MATCO05cs+R8F3y44KaQQWcTeCIjuTnLN38v8JO2mxPHV5MlR74gQWaAiSdgq2tPhtyof8msmXZLkviyjVXgQWDDLCdCbG8/38s1PyHcV4aUPHcaxZDgQW8WwovZLBdNmcgDYIB7NwrRnu/vBgfwQW51qthQuRvnMUe3ngBvV7ZyNnu3huCzCCAhAEFuvjGeQPaU83CpkDLTXPF5izOHKktDgEFtkHNxI4MpcT/v7mabNIC/l9LzGgB6oEFt5286Dy+6E2LogmmEcy6ipDrbYwNB4EFhX/c4/fWjLm7SsGsrCWa30ODUFdN9wEFo3IsdCRHUQ2gRm1C//HN+M5Kezbf44EFr2UnpeAU1PviUWeIj1S071VvzWx6TEEFibzLoxMYfVdDIjeXxzt4WPrVL7mkcQEFmP/K8iEurlGiKAOS1BIEyW3IM82UfsEFn+2eD4ZdQ4XtkSVjwvVdI2O3P4LWlQEFpIEJ9OvMqE94b2ZqWbHPo7HEH4k/MkEFp3uELJxYT1KcuBXSdyFiozMrCj7viAEFvTC6jMNDrguYMie1UiKStdkGyRnHfUEFsd8WsQV0N3bGeIKBB/kgNuVzboAXuoEFrIlNop2vzqvBPuZ4ZCjvX72nV3RLEcEFqTjHjs8FkA4w2Un3nhq0P3eBb0u1QgEFtrn3kPrjzIbVxEsgSXqGKTM/K3WRkYEFgJfUyCpd0pygxPNcKpvSVj4T5ftX/8EFtjaKxmkW2/XKZwFYsX0Q96601P9unEEFnFAmGK8vd1JW/qgK4z2B1lIXP6qX1wEFsZo7U0EcFhZfwaX4T4hNlHysn9I5ioEFgTOLS7B/iHxmtTdXQRi2suDOjxL3uUEFhzU5QDAqg5iGPk+tb7o/xO0xtqmDwYwggIQBBbu2Gshe3XkStX3DryRwqM4buWq9pMRBBauqNjt/7v73KsIB2+ZHltrKBUe3kIwBBY1JMCbGVBdncRJFzoXcIcev9lVF8P4BBamx57KhpJC5HHEExwXZj4mGyfB/WdxBBb/pb+qAX6SlUBzmZsAr4cjONfH261kBBZZwkO4rRfyHxzPwX0wUkL8rBgzb2kCBBYL5IMEDWrSyyk3TOWtoQ5/L390vAa9BBaf61Y4yAJr4xIy48kQB/biU7u/isOSBBZOaa1ArXqBjT5a/47m3gZvy1PmjM4aBBZCs01Rog7AGbKOhRLC5A3N6ocNTp3oBBaKnYaSjoMk3RluCLwRYrykRmskXE+WBBbPGEetAedEuVu4jYv0bMnDZ8ZP7HQtBBbFFARCU9ibf5uvdZ+tJI1ZCqJBb/uXBBa1mDck2UIYjE0Noj7+Z/nHG34Tao5hBBbImoF5PVMzthfrpWLhyRo2BIKGO+EkBBbLDk2Ze13jAtMiojrZGeDKyFO3TmtdBBbOV8DwdEOuTsV29qI2DWw+WuJL0xxKBBaAtly1TR9xCpvktIdpxlNp0lvtNVncBBYB6rGb0DsOdQ0rpZhEF3bdvNOyhE6WBBZ8y+Q0ocmpZShhcWLZmZOaW/xMMfkmBBbCQZb7OMJsDukJPHhgJ+Cd8dLgJPcuBBbJOmw8QGpJ+PIbS94loL0QYqqYt0DrMIIBgQQhTmY0MFwmKKCjtIc7tC42h0RfwhB01p2DzCtbLPrc8CySBCHWO+PFk2c19RWtabr0tQl+ukAwuYDG+nRSOsTKiuKPR70EIWtPF6eFDNd3q9qcK2yz3Hhb9KlIXSe8OPlC5DgJmywc3AQhXmy49/i7BxRq1T64t2uD4BDd/uEVI0XRlSZv6iZfbxpYBCGVc/fN28u/fR5D/p5EGIhyOb39jecZxggxFD2J7C86s28EIUd1PuwRmsNDd0XByHcAWlmABDt+XbkQDY0jgqqz2fXeSgQhoB69H0rGOJMi8akxByUmWpVDii+W15MEUnHkWCIO4tD6BCGmaOYzJs6Thj2zrC2nF/kWYguI9p2b6QE8OjcDKkQt2QEEIdNOTLpf5rkD4tAcxTe8c8XjR1d4hiX9iXb3VVvRInyoowQhpYk1USJeWUE867sZXblsoIZwWNUxb3wBIKO1MZKEVm5fBCEHHpY9vdu5V6dVLK1zvUpue0wu3rXhKjpQaPvAfjFyJJoEC5btyc/MB5StXAHF public key: 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 message=13120983870;signature=base64:8NOJCh5cPzmis+XaZu5Ploh47PlUQz8tv2I6Jm5wDlf5 true false     @org.junit.Test public void test3() { String message = "13120983870"; Provider provider = new BouncyCastlePQCProvider(); KeyFactory keyFactory = null; try { keyFactory = KeyFactory.getInstance("Rainbow", provider); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } Signature signature = null; try { signature = Signature.getInstance("SHA512WITHRainbow", provider); } catch (NoSuchAlgorithmException e) { Assert.fail("no such algorithm: " + e.getMessage()); } try { signature.initSign(privateKey1); } catch (InvalidKeyException e) { Assert.fail("invalid key: " + e.getMessage()); } byte[] sign = null; try { signature.update(message.getBytes()); sign = signature.sign(); } catch (SignatureException e) { Assert.fail("signature: " + e.getMessage()); } System.out.println("signature: " + Base64.byteArrayToBase64(sign)); signature = null; try { signature = Signature.getInstance("SHA512WITHRainbow", provider); } catch (NoSuchAlgorithmException e) { Assert.fail("no such algorithm: " + e.getMessage()); } try { signature.initVerify(publicKey1); } catch (InvalidKeyException e) { Assert.fail("invalid key: " + e.getMessage()); } try { signature.update(message.getBytes()); boolean result = signature.verify(sign); System.out.println(result); Assert.assertTrue(result); } catch (SignatureException e) { Assert.fail("signature: " + e.getMessage()); } signature = null; try { signature = Signature.getInstance("SHA512WITHRainbow", provider); } catch (NoSuchAlgorithmException e) { Assert.fail("no such algorithm: " + e.getMessage()); } try { signature.initVerify(publicKey1); } catch (InvalidKeyException e) { Assert.fail("invalid key: " + e.getMessage()); } try { signature.update("13120983871".getBytes()); boolean result = signature.verify(sign); System.out.println(result); Assert.assertFalse(result); } catch (SignatureException e) { Assert.fail("signature: " + e.getMessage()); } }     private key: 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 public key: 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 signature: DcXR1dk2+m0fxg+Ght5dusWPXkheNHNHE+3EMkXLek4e true false   通过Java 标准api方式:KeyFactory,KeySpec生成公私钥,并进行签名和验证操作: private void signAndVerity(String message, PrivateKey privateKey, PublicKey publicKey) { Signature signature = null; try { signature = Signature.getInstance("SHA512WITHRainbow", provider); } catch (NoSuchAlgorithmException e) { Assert.fail("no such algorithm: " + e.getMessage()); } try { signature.initSign(privateKey); } catch (InvalidKeyException e) { Assert.fail("invalid key: " + e.getMessage()); } byte[] sign = null; try { signature.update(message.getBytes()); sign = signature.sign(); } catch (SignatureException e) { Assert.fail("signature: " + e.getMessage()); } System.out.println("signature: " + Base64.byteArrayToBase64(sign)); signature = null; try { signature = Signature.getInstance("SHA512WITHRainbow", provider); } catch (NoSuchAlgorithmException e) { Assert.fail("no such algorithm: " + e.getMessage()); } try { signature.initVerify(publicKey); } catch (InvalidKeyException e) { Assert.fail("invalid key: " + e.getMessage()); } try { signature.update(message.getBytes()); boolean result = signature.verify(sign); System.out.println(result); Assert.assertTrue(result); } catch (SignatureException e) { Assert.fail("signature: " + e.getMessage()); } signature = null; try { signature = Signature.getInstance("SHA512WITHRainbow", provider); } catch (NoSuchAlgorithmException e) { Assert.fail("no such algorithm: " + e.getMessage()); } try { signature.initVerify(publicKey); } catch (InvalidKeyException e) { Assert.fail("invalid key: " + e.getMessage()); } try { signature.update("13120983871".getBytes()); boolean result = signature.verify(sign); System.out.println(result); Assert.assertFalse(result); } catch (SignatureException e) { Assert.fail("signature: " + e.getMessage()); } } @org.junit.Test public void test_1() { String privKey = "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"; String pubKey = "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"; byte[] privateKeyEncoded = Base64.base64ToByteArray(privKey); byte[] publicKeyEncoded = Base64.base64ToByteArray(pubKey); String message = "13120983870"; System.out.println(message); PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKeyEncoded); KeyFactory keyFactory = null; try { keyFactory = KeyFactory.getInstance("Rainbow", provider); } catch (NoSuchAlgorithmException e) { Assert.fail("no such algorithm: " + e.getMessage()); } PrivateKey privateKey = null; try { privateKey = keyFactory.generatePrivate(pkcs8KeySpec); } catch (InvalidKeySpecException e) { Assert.fail("invalid key spec: " + e.getMessage()); } System.out.println("private key: " + Base64.byteArrayToBase64(((Key) privateKey).getEncoded())); X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKeyEncoded); try { keyFactory = KeyFactory.getInstance("Rainbow", provider); } catch (NoSuchAlgorithmException e) { Assert.fail("no such algorithm: " + e.getMessage()); } PublicKey publicKey = null; try { publicKey = keyFactory.generatePublic(x509KeySpec); } catch (InvalidKeySpecException e) { Assert.fail("invalid key spec: " + e.getMessage()); } System.out.println("public key: " + Base64.byteArrayToBase64(((Key) publicKey).getEncoded())); signAndVerity(message, privateKey, publicKey); }  

已有 0 人发表留言,猛击->>这里<<-参与讨论


ITeye推荐



]]>
Thu, 17 Jan 2019 23:50:17 +0800 https://lobin.iteye.com/blog/2436748 https://lobin.iteye.com/blog/2436748
ITeye Java编程 Spring框架 Ajax技术 agile敏捷软件开发 ruby on rails实践 - ITeye做最棒的软件开发交流社区 - 乐虎国际|授权平台 哈希签名:哈希函数(hash)在数字签名中的实现思路   以下代码实现上的思路来自:Constructing Digital Signatures from a One Way Function, 文档资料源自http://lamport.azurewebsites.net/pubs/dig-sig.pdf, 这个是我下来上传的地址:http://dl.iteye.com/topics/download/f80e7b49-8d9c-30bb-9db9-8b3df6171465   public class HashDigest { private static byte[] privateKeyEncodedPart1 = null; private static byte[] privateKeyEncodedPart2 = null; private static byte[] publicKeyEncodedPart1 = null; private static byte[] publicKeyEncodedPart2 = null; @BeforeClass public static void init() { privateKeyEncodedPart1 = new byte[256 * 8]; privateKeyEncodedPart2 = new byte[256 * 8]; for (int i = 0; i < 256; i++) { Random random = new Random(); byte[] bytes = new byte[8]; random.nextBytes(bytes); System.arraycopy(bytes, 0, privateKeyEncodedPart1, i * 8, bytes.length); random.nextBytes(bytes); System.arraycopy(bytes, 0, privateKeyEncodedPart2, i * 8, bytes.length); } publicKeyEncodedPart1 = new byte[256 * 8]; publicKeyEncodedPart2 = new byte[256 * 8]; for (int i = 0; i < 256; i++) { byte[] t = new byte[8]; System.arraycopy(privateKeyEncodedPart1, i * 8, t, 0, t.length); t = hash(t); System.arraycopy(t, 0, publicKeyEncodedPart1, i * 8, t.length); System.arraycopy(privateKeyEncodedPart2, i * 8, t, 0, t.length); t = hash(t); System.arraycopy(t, 0, publicKeyEncodedPart2, i * 8, t.length); } byte[] privateKeyEncoded = getPrivateKeyEncoded(); System.out.println("private key: " + Base64.byteArrayToBase64(privateKeyEncoded)); byte[] publicKeyEncoded = getPublicKeyEncoded(); System.out.println("public key: " + Base64.byteArrayToBase64(publicKeyEncoded)); } private static byte[] getPrivateKeyEncoded() { byte[] encoded = new byte[privateKeyEncodedPart1.length + privateKeyEncodedPart2.length]; System.arraycopy(privateKeyEncodedPart1, 0, encoded, 0, privateKeyEncodedPart1.length); System.arraycopy(privateKeyEncodedPart2, 0, encoded, privateKeyEncodedPart1.length, privateKeyEncodedPart2.length); return encoded; } private static byte[] getPublicKeyEncoded() { byte[] encoded = new byte[publicKeyEncodedPart1.length + publicKeyEncodedPart2.length]; System.arraycopy(publicKeyEncodedPart1, 0, encoded, 0, publicKeyEncodedPart1.length); System.arraycopy(publicKeyEncodedPart2, 0, encoded, publicKeyEncodedPart1.length, publicKeyEncodedPart2.length); return encoded; } // 仅演示用 private static byte[] hash(byte[] input) { byte[] bytes = new byte[input.length]; for (int i = 0; i < input.length; i++) { bytes[i] = (byte) ~input[i]; } return bytes; } public byte[] digest(byte[] input) { byte[] digest = new byte[input.length * 8]; for (int i = 0; i < input.length; i++) { int j = input[i] % 256; if ((i & 0x01) == 0) { System.arraycopy(privateKeyEncodedPart1, j * 8, digest, i * 8, 8); } else { System.arraycopy(privateKeyEncodedPart2, j * 8, digest, i * 8, 8); } } return digest; } public boolean verify(byte[] input, byte[] digest) { for (int i = 0; i < input.length; i++) { byte[] t = new byte[8]; System.arraycopy(digest, i * 8, t, 0, t.length); int j = input[i] % 256; byte[] b = new byte[8]; if ((i & 0x01) == 0) { System.arraycopy(publicKeyEncodedPart1, j * 8, b, 0, b.length); } else { System.arraycopy(publicKeyEncodedPart2, j * 8, b, 0, b.length); } b = hash(b); for (int k = 0; k < t.length; k++) { if (t[k] != b[k]) { return false; } } } return true; } @org.junit.Test public void test() { String message = "13120983870"; System.out.println(message + ", base64: " + Base64.byteArrayToBase64(message.getBytes())); byte[] digest = digest(message.getBytes()); System.out.println("signature: " + Base64.byteArrayToBase64(digest)); boolean result = verify(message.getBytes(), digest); System.out.println(result); result = verify("13120983871".getBytes(), digest); System.out.println(result); result = verify("13120983879".getBytes(), digest); System.out.println(result); result = verify("abcdefg".getBytes(), digest); System.out.println(result); } }     private key: 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 public key: opULz8/Kv8e2DZx2nsjkWHJFECiz8HDYNH25e03gcxMJZkVPntKC+hqJ95hnXThYbGb9aqVelt5Az6YPkJ6cpYktKwMgFJ+NMG2AHhjS5NlI2qW27DvIqNMiUWLj8DkkgUPq+NYHRQL56jjXdKkFejjVD+EEgltDJ8IceBzc3Be3WYyc0UCsvibcr4q5YENH8fCa8Z2QLeFHGJYv8qTfW4XNbabRrvnSFnWJbOnoWkyUURMIlaaD05Oop5kNkqBFGJgrXtlE27FDRuU+RWM+t8MIAWLMMvrSWfyHM+nJft017M5N2PClJNc5i9bFrLMxvwkCX6QaNooybO1FyMoxkUqxsCit/TylehdMaCHTAb1FO5KgMyhJroLAQtQ3fyxdszUpQHTIRRlC/cSzJ6YmnYeicLRSBETkCjTvvivMkwDVHOL8hha/H8TtkESG+ZvX1jKu+VM+xzdorc+MdrMJOq8K9/Jmqiq6d3+MpoNnonVbB6yjfb2hscHOAU+MxMU8wRSWbFQiKkh9Iu19xbSlk+BWPHUkI/9trExVIXa5AB7T3whWOY6CCN0hI5ZgFoesrVFPGfF+ITrKr+HFls1ev7Fdaio2LFuVXcNlgfEqkiMwQ51NaGw3LPSIQ2+80mAw7MkJzyPQ0y+z6HMPdmbD4niwDJFuSCi3CJWfV29+tGE9SGK78d44MLqe5oyDS9vcwH8NQo/FTJX6WLXiQGYQ5sqb853T7RjqxYIzgJZFuThFw/C/WIri6PF/hZ+vTlWHve0jh6uH6qeo2rQ1WET0Ij3yJzB5+Gl7+N1ZDYtJVJ5FPjsfzdeka7rN0VCOIMlcT0NW/iBiMPrv3vzolB9rGCT61jTd9GkGCQ5UABXqIhyUytitt3hUknXUrB8JBxupGEOOCqxq8BAm/sKPx0Iy2YPsFSG76ceuPK0W3eW+2keUF/WWTsyuD4OYiYsAUYLvtCCRh/A3S+350DgQvgPBcrQGlR+H6jwIPvkzwY7RrnDUhNbmNficQyLWDVF4JgonBwcOpIlwI8glUUutfYTYqgyrySqJPu+tQT2ywYG7Mc5I89KiFYhEXqPywHE2EY6pBLVZBNKR/MTJrG1imLOfyEL/9LA6LjmC4wmIkKpC1w3HnVlofY61IKAADQcDrT0QfwoDGWwE4swKtrKEJiSs9vE0SjYCYv6VDzC34UUe5SbpM0nBlk+WduGj2k6U4gnYP9hrQP/O9mxjju0hSW9elufnXpK8HJ+ERIAHlCb+RjCD32hgtiw/zUGReXKIqTXIm5Tqv0r1GUdUGPbOI0eH1ruNNvARNN7JrDc6S1NSVG4XQIph95bbs9lGoZYP5VjBq2wwU/EKqvUbaJsgMyhOqTyR3srFaDw6Bi7+JB3fcTHhMVT8aDQrPT6c+0o/0BX4RseI1H01Uju4tL1Mt12tnVkz0HlopCbWYfRX4fene51wYMdnq0JA7KQcsvjMThRN1/qvSJlwUqZi5Rr6fHZ65XpwJBJZQQIyDKAZYSZobJUi0waeRAnEETDvkT4py2P6z+b4yKMNWVErOcbGRY6zqOym8A61Hdbmsbsg5CS0lwz41S8Xn2fGnMfJnkmq1/aNW7sQg8p3dBOYLFdjbxTzG+4ipNT5Yev1Ac9Q+Dy7zLf7UpG1o3cWq4wUXZbBTwq7Y+ecHjC5M5SzsxDNPPd7jWTc8Jg+S16me+EpefFPk4T6SO2dLE8q8eQO6s0aSBuOR0vSxcDeROtzOhV26gcAkyPNj+gIBSMytkS00ECgNddkUM62mqLMVJ436BcdJO0lldBj4LVu+3e1oWK583FWcXibQzo5uCCJpoI4fRjzqIEFuQHROUGc0L8nTIQLuYWvDtTJbCPOqY+aX5jY8zZ3QdvNYgdpoHkJ/p0q3vC/drSC/uLk2vu7g4RUOXLs+Waozw8pzqY221hU6uLhlzxVZp3shNfN+XRdt8SorBCjkkuhuxUJMcxUqU6wJ9lhgZ1woV3zudbXhUfI3QjaDKo9DMLzEMtTom3Fv/LV9h8HRSmE1gzAwFwU0eecsrBjfKrvKswOqWs2B+ZsDInGsypGJch9l2Kax5tW9E5mAoEsI+97Y2yMDt3+icf24ARqwlAG+ZTbiNpJrh3U0UsdnotDjHp9+KhunPhi7dLxKOAFGrnOuhNttWMYWRewLdToPfp4qTMcLhozJQXsHPWbDHfQhR5tt/uNwMw/uBp3ZGQ20Fz19blP2TEbvct0APjKMlnbH2mDRpSdSJ4wuofVFo+9Y7Hu2oXL0zHjKzLPBdFFOxZqGMKkd+Cf/4ZBkmrzv5GbBvtVrTMZcWFMjTmH+qOw/aexT22Jga+S6OAv30hVGCQVeb8H6pKamGK+zqQsI/2jB9cAiu91KiJcZqR7K18L7cY+UamFBovvBD25H0uh94+zBC92PvF9pvQ2eQgByAr4+09n986EkSXs+RwhNgKjO5ip21rSV2tZdTjTCAVomdpNjFxNw+eMAEI/n/iEKnu9WGfaDUdWCOKtzbjEOGZXJo5l23NLfi7ih6YK8XWPbp0/9z+HekNWXfhXvOeF/nRTYHbzf8bnJIUufIR8ctq1RU4gR0FU6hTTsNdqbQFbCum3lonzqpLLl5hYgwqG59InXlyZP0CqMYbKnhihSJAyDJkYrA7VntUNh301v4P6rZVDaJtEcdepQdAx0mX+xt0Ucg7nFtWQKvXjcl1pxi20bLJ4Iq7qjMAT6qEMmCJMMJFQ6LACYHgBWrjc6Oxoqt5tl8ZE1BTBZ1T6z2BV5Qkt6PKb4v7We0DFBOv8ukWgvzKOSOneA3ADeQYa32dcSOPi3swuNrt1z4SCNCRNfcIu4e6Jxwpp4Nw7GcSnqGhnehW8lq2TGwo6onqONuJbuVIDl36c8PzDtXDJn1WyuKquQPPBHDq5V/45LsKNDYYdjJ4DBcTNl6ms11cBmFS/zVA4s4N6RxObXWaZt8JDgWXpmXheFVk3etXoXFHt1m60dZ8h+1v0McEqrEw5hmA7S3eJpTrj6rDPAh6IsfyzpW08ugeHgAACp6VaFV5s6sAfC5/WS6lixnIs/N+LdjpAQs0WpwM0Erh+WoLDhVot6HNjAM4tmtNiHwOAxrYmD7lW+1XU0RikPHZMEAkl9Xorwg44bjWjo0qXv+Xw6YqJ2hcD+4Dlkg1NDZlEdVTS1phEMxL9OzZARX2hzhQZZuEuHkWBHWbzEdVPxZ1Qq0mnI5Lqgmf9cFn0JOqSO1jYEmTJN9Apod7ti1l7Yw40jNtEIBD0/5Hm5+tW+wRwf0iZPIZkOrajmQzcjy4oLZX5xNWQBvx39eVjrYl+82H9+jk1HXuKov9StU0C1LMY/gek3jnZ9nURQQufp8DliEigde5KrtWk0E3FZ1qwRvoOgAvE/xrSdyjBORoQAeHBfXpmTmQht5h+VFiGA9sx3kuf/Wo+NFeUa0Q58U/pdiBiMQ8xcQ+Cq5CjuoE27m1OaBuBjvrA10IMqMpUcV1HR4xqB5/LpB6THwFw7eRGZV6wRrzT4rKJBc5K8qvDFBSs5IH9flFW/eCh5dihBOQ1mLF7QVmHoLfsWAC6kR7GLxcJxqC1XYdn3XvQbJgS0fFcn1GZHCNezhkOJ6BeVtYrVYMLCXoBfM9mNIQpTfZooskomKck301AXF7QIs7nGtSdfOpsuIM0yze5dVVe1n1VOFb1PtnSiZ1RRRA+fDd0VJqYTBvXClfxI+fR04y7ZzjOtMbaRfKNRBve/iPH+klE/DfH4XhX71t+rWe+glEdsvEDvoapa2u/w1mfGq6/gFcKKEdGKQDpvybajxSJAwL2jBKOKWTeLfnyW2yc8QT1+dRekmatIbKGBPsHvHUo/Nz5lSFPFxJlb6b40+hbiXh+dthQpfeFuesjeZxeVXRqmc3MdC5ofZAyJFu614wa/Lzvu1lnUlfUVADVbDSuSpqxisydxz6Q8MGfUfwOhNbpLtxrXPJiyYYbfg2xAh8MMeo6RZAY1me88pynH9IMoOlK5csCiyzjyYWxLoJCSi4DNyih+dHiorIcN3gJyRLuWst2MULZCiJ3Djs4drdoHz/dU4kDc4xBj1g7GJRjtH8+Yn/eCK1prBGGJenuAGiB5a9q/mpb6MNFGnMBKaJBcJc0+lyXMxT7Wj+RnEHAZ3axKgp55TDFS38q+t7Z4v3cNtJgcNbgVwbXf4neW400TSHOT0qay4+njcRIGP/cDR0OcZMHxuH8Efba18/XpZTozlSpG8wtzLl72lJat6auISvuAPUhmV/viC9uuJIY+j9FIOA/ni+x77pLy4yKQysy+UedKca2UctJDfIDWCTzswRvss5tZt54ito1Y6riW/72BGTg/kuNgzWg1egfL/8aWa105IjcIN+zZ+KoMAubF19UnQ4zpv1FRr8HR6OaYJ+qPYaAPI50QldVyUwEAPuGq7+jGJg8a57EJyLgPUq2BoJl5RoTpII1PVJO6EkTAXqR41o+++xVvbhWtdWe6/5pxsYQg42BilyaM1nl9Du1URHzwvramFO8HlWQ24mOq6cCFSH7RCKvq01Hx0vctTMk64DKGivQqZbTJKGz+iei/gpsjYzAWIkF9R8ijCn95nDTknFbFlc+IGOVsJUNBbyxOBing3f+V+FXTvS16gbD7SNr6sv1fFF9BbnN7ZY/Chg9saGA8OC3JFEgr9mtIJHClNRZW+XsgaJOXa82IurVIrQzGlA/vdw0B76bVmU1qX3CC4wcX09lYzDJC9gM6S6FGVNJFe5XUjIjWvVULL4X3G0Z1W8VHU/kgZHX2M15zfONMGY1XMFQQgIeWeHO4jVWGdxbhVf7Se/eIcGPmVjH+jyVN4HN89vcTZvYo1ehawiqkCSWoXYUcvP4YuAlq2OaEZCA7N77NuAwqKrvL0XmLt89rB6569REEtTAkOJUxNED7YZoaH+siPRmldI9CiOlFNzqG4JoFyDXKwUAjmxTIchdtpMyPj28xe5E1Cv/+CGhlHkoSH9MF9YYqar9/Skso0Ljdl8ApYocLHoPjVCP+WQjjJ5/vsysZiIY43M0TrEyD4aI/8FlMNprGF9n0MTAQbP+G8kR71zpZXtai3lq+qUYK9wC3WpM6YquHw3WenILBNOrh9zVammJsbSexRQm0i1s70nAOsBtEoxPsnJNp4cMIL781Z8p9Ys9T5s63O0UV+UEKKCct397excltYwj6rEhnkurkWdnLp6E4HV6A/cvfxkO1/pwSkoZfINSOP0dPQ0qs8jbeZWT4cqoI1xNCulupGRkPw/9APkELIcu4N5RMET/zcXtuCGXsP8qb6MvgWbiToMz/MrYSDJp09dr/rgsZ5NDRw4KZQ0UGqVPK9HY92niecg6bux0zTFtM+W+vIBFVKW9NvvCzWeI7VEtHDujOsOlyOBod7Xo4UyrfXzfy3nExqXhOWp73LuyCqCteCtVy0RWpwZhK7j70hmF7p1cZehCIr5KRQ== 13120983870, base64: MTMxMjA5ODM4NzA= signature: gt0SgjpLWmyPgLdmw3mbxYLdEoI6S1psAG4ZGBSpBPs+62mTq93Vt+cB+FshxiYJTqKV1cnTpGqPgLdmw3mbxU6ildXJ06RqngIFxsrihHU+62mTq93Vtw== true false false false   1、Constructing Digital Signatures from a One Way Function, http://lamport.azurewebsites.net/pubs/pubs.html#dig-sig 2、Constructing Digital Signatures from a One Way Function, http://lamport.azurewebsites.net/pubs/dig-sig.pdf      

已有 0 人发表留言,猛击->>这里<<-参与讨论


ITeye推荐



]]>
Thu, 17 Jan 2019 02:47:29 +0800 https://lobin.iteye.com/blog/2436715 https://lobin.iteye.com/blog/2436715
ITeye Java编程 Spring框架 Ajax技术 agile敏捷软件开发 ruby on rails实践 - ITeye做最棒的软件开发交流社区 - 乐虎国际|授权平台

Dagger: A Memory-Hard to Compute, Memory-Easy to Verify Scrypt Alternative

Over the past five years of experience with Bitcoin and alternative cryptocurrencies, one important property for proof of work functions that has been discovered is that of "memory-hardness" - computing a valid proof of work should require not only a large number of computations, but also a large amount of memory. Currently, two major categories of memory-hard functions, scrypt and Primecoin mining, exist, but both are imperfect; neither require nearly as much memory as an ideal memory-hard function could require, and both suffer from time-memory tradeoff attacks, where the function can be computed with significantly less memory than intended at the cost of sacrificing some computational efficiency. This paper presents Dagger, a memory-hard proof of work based on moderately connected directed acyclic graphs (DAGs, hence the name), which, while far from optimal, has much stronger memory-hardness properties than anything else in use today.

Why Be Memory-Hard?

The main reason why memory hardness is important is to make the proof of work function resistant to specialized hardware. With Bitcoin, whose mining algorithm requires only a simple SHA256 computation, companies have already existed for over a year that create specialized "application-specific integrated circuits" (ASICs) designed and configured in silicon for the sole purpose of computing billions of SHA256 hashes in an attempt to "mine" a valid Bitcoin block. These chips have no legitimate applications outside of Bitcoin mining and password cracking, and the presence of these chips, which are thousands of times more efficient per dollar and kilowatt hour at computing hashes than generic CPUs, makes it impossible for ordinary users with generic CPU and GPU hardware to compete. This dominance of specialized hardware has several detrimental effects:
  1. It negates the democratic distribution aspect of cryptocurrency mining. In a generic hardware-dominated ecosystem, the fact that everyone has a computer guarantees that everyone will have an equal opportunity to earn at least some of the initial money supply. With specialized hardware, this factor does not exist; each economic actor's mining potential is linear (in fact, slightly superlinear) in their quantity of pre-existing capital, potentially exacerbating existing wealth inequalities.
  2. It increases resource waste. In an efficient market, marginal revenue approaches marginal cost. Since mining revenue is a linear function of money spent on mining hardware and electricity, this also implies that total revenue approaches total cost. Hence, in a specialized hardware dominated ecosystem, the quantity of resources wasted is close to 100% of the security level of the network. In a CPU and GPU-dominated ecosystem, because everyone already has a computer, people do not need to buy specialized hardware for the first few hashes per second worth of mining power. Hence, revenue is sublinear in cost - everyone gets a bit of revenue "for free". This implies that the quantity of resources wasted by the network is potentially considerably lower than its security parameter.
  3. It centralizes mining in the hands of a few actors (ie. ASIC manufacturers), making 51% attacks much more likely and potentially opening the network up to regulatory pressure.
Specialized hardware is so powerful because it includes many thousands of circuits specifically designed for computing the proof of work function, allowing the hardware to compute the function thousands of times in parallel. Memory hardness alleviates this problem by making the main limiting factor not CPU power, but memory. One can also make a modest improvement by targeting CPU clock speed, but the extent to which such optimizations can be made is fundamentally limited to a very low value by technological considerations. Thus, improvement through parallelization hits a roadblock: running ten memory-hard computations in parallel requires ten times as much memory. Specialized hardware menufacturers can certainly pack terabytes of memory into their devices, but the effect of this is mitigated by two factors. First, hobbyists can achieve the same effect by simply buying many off-the-shelf memory cards. Second, memory is much more expensive to produce (if measured in laptop equivalents) than SHA256 hashing chips; the RAM used in ordinary computers is already essentially optimal.

Algorithm specification:

Essentially, the Dagger algorithm works by creating a directed acyclic graph (the technical term for a tree where each node is allowed to have multiple parents) with ten levels including the root and a total of 225 - 1 values. In levels 1 through 8, the value of each node depends on three nodes in the level above it, and the number of nodes in each level is eight times larger than in the previous. In level 9, the value of each node depends on 16 of its parents, and the level is only twice as large as the previous; the purpose of this is to make the natural time-memory tradeoff attack be artificially costly to implement at the first level, so that it would not be a viable strategy to implement any time-memory tradeoff optimizations at all. Finally, the algorithm uses the underlying data, combined with a nonce, to pseudorandomly select eight bottom-level nodes in the graph, and computes the hash of all of these nodes put together. If the miner finds a nonce such that this resulting hash is below 2256 divided by the difficulty parameter, the result is a valid proof of work. Let D be the underlying data (eg. in Bitcoin's case the block header), N be the nonce and || be the string concatenation operator (ie. 'foo' || 'bar' == 'foobar') . The entire code for the algorithm is as follows: spread(L) = 16 if L == 9 else 3 node(D,xn,0,0) = D node(D,xn,L,i) = with m = spread(L) p[k] = sha256(D || xn || L || i || k) mod 8^(L-1) for k in [0...m-1] sha256(node(L-1,p[0]) || node(L-1,p[1]) ... || node(L-1,p[m-1])) eval(D,N) = with xn = floor(n / 2^26) p[k] = sha256(D || xn || i || k) mod 8^8 * 2 for k in [0...3] sha256(node(D,xn,9,p[0]) || node(D,xn,9,p[1]) ... || node(D,xn,9,p[3])) Objective: find k such that eval(D,k) < 2^256 / diff

Properties:

  1. With 225 memory (ie. 512 MB, since each memory unit is a 32-byte hash), the optimal algorithm is to pre-compute the 224 leaf nodes run eval with all 225 possibilities. The main computational difficulty is computing SHA256 hashes. Each node in levels 1 - 8 will take two hashes, so the levels will take up 2^25 - 4 hashes in total (not -2 since the root node requires no hash). Each node in level 9 takes 16 hashes, adding 228 hashes, and then each nonce will take 8 hashes, adding 228 hashes once again. Thus, running through 226 nonces will take 229 + 225 - 4 hashes altogether.
  2. One potential problem is lazy evaluation; parts of the tree can be evaluated only as needed in order to reduce the number of hashes required. However, because a (pseudo-) random node out of 225 is taken 228 times, we can statistically estimate that each node has a 1 / e8 change of remaining unused - only about 0.03%. Hence, the benefit from lazy evaluation is insubstantial.
  3. It is possible to run the algorithm with very little memory, but one must re-compute the eight bottom leaf nodes that the proof of work result on each nonce depends on each time. Naively doing an exponential calculation, we get that 38 * 16, or 104976, steps are required to compute a single nonce. In practice, many values are reused, so only an average of almost exactly 6000 hashes is needed, but this is still a very large amount - the memory-based algorithm manages a mere 8 computations per nonce, giving low-memory hardware a 750x penalty.
  4. Verification requires computing one nonce without pre-computation, so it also takes 6000 hashes and about 160 KB of memory.
  5. Because each node in the last level has 16 parents instead of 3, the time-memory tradeoff attack is severely weakened - attempting to store 8 levels instead of 9 reduces memory usage by a factor of 2 but slows down computation by a factor of 16. Thus, no practical time-memory tradeoff attack exists; close to the full 512 MB is required for any reasonable level of efficiency.

Conclusion

This algorithm provides a proof of work mining function with memory hardness properties that are not ideal, but that are nevertheless a massive improvement over anything available previously. It takes 512 MB to evaluate, 112 KB memory and 4078 hashes to verify, and even the tinest time-memory tradeoff is not worthwhile to implement because of the bottom-level branching adjustment. These parameters allow Dagger to be much more daring in its memory requirements than Primecoin or scrypt, asking for 512 MB of RAM for a single thread. Because the primary determinant of hardness is memory, and not computation, specialized hardware has only a tiny advantage; even an optimal Dagger mining ASIC would have little to offer over a hobbyist purchasing hundreds of gigabytes of memory cards off the shelf and plugging them into a medium-power GPU. And even in such an equilibrium, mining with ordinary CPUs will likely continue to be practical.

Appendix: Why 6000 hashes?

To compute the required four values in level 9, one must look at 64 randomly selected values in level 8. With negligibly less than 100% probability, these values will all be different. From there, suppose that you have computed V[n] different values for level n. You will need to make an expected 3 * V[n]queries to level n-1. Because the queries are pseudorandom, after these queries the probability that any individual cell will remain empty is (1 - (1/8^n)) ^ (3 * V[n]). Hence, we can estimate that the expected value of V[n-1], the number of cells that will not be empty (ie. will need to be computed) is close to8^n - 8^n * (1 - (1/8^n)) ^ (3 * V[n]). We thus have a recursive computation: V[8] = 64 V[7] = 8^7 - 8^7 * (1 - 1/8^7) ^ (64 * 3) = 191.99 V[6] = 8^6 - 8^6 * (1 - 1/8^6) ^ (191.99 * 3) = 575.34 V[5] = 8^5 - 8^5 * (1 - 1/8^5) ^ (575.34 * 3) = 1681.38 V[4] = 8^4 - 8^4 * (1 - 1/8^4) ^ (1681.38 * 3) = 2900.72 V[3] = 8^3 - 8^3 * (1 - 1/8^3) ^ (2900.72 * 3) = 512.00 V[2] = 8^2 - 8^2 * (1 - 1/8^2) ^ (512.00 * 3) = 64.00 V[1] = 8^1 - 8^1 * (1 - 1/8^1) ^ (64.00 * 3) = 8.00 V[0] = 8^0 - 8^0 * (1 - 1/8^0) ^ (8.00 * 3) = 1.00 V[0] + V[1] + ... + V[8] = 5998.43 This computation is not quite accurate, since EV(f(x) is not the same as f(EV(x)) (EV = expected value) if f is not linear, as is the case here, but because we are not dealing with especially fat-tailed or skewed distributions the standard deviations are sufficiently low for this inaccuracy to have no substantial effect.

Acknowledgements

  • Thanks to Adam Back and Charles Hoskinson, for discussion and critique of earlier drafts of the protocol
  • See also: Fabien Coelho's paper, in which Fabien Coelho had independently discovered a similar algorithm in 2005.
  1、http://www.hashcash.org/papers/dagger.html 2、https://github.com/ethereum/wiki/wiki/Dagger-Hashimoto  

已有 0 人发表留言,猛击->>这里<<-参与讨论


ITeye推荐



]]>
Wed, 16 Jan 2019 01:32:43 +0800 https://lobin.iteye.com/blog/2436670 https://lobin.iteye.com/blog/2436670
ITeye Java编程 Spring框架 Ajax技术 agile敏捷软件开发 ruby on rails实践 - ITeye做最棒的软件开发交流社区 - 乐虎国际|授权平台   Digest public interface Digest { /** * Insert one more input data byte. * * @param in the input byte */ void update(byte in); /** * Insert some more bytes. * * @param inbuf the data bytes */ void update(byte[] inbuf); /** * Insert some more bytes. * * @param inbuf the data buffer * @param off the data offset in {@code inbuf} * @param len the data length (in bytes) */ void update(byte[] inbuf, int off, int len); /** * Finalize the current hash computation and return the hash value * in a newly-allocated array. The object is resetted. * * @return the hash output */ byte[] digest(); /** * Input some bytes, then finalize the current hash computation * and return the hash value in a newly-allocated array. The object * is resetted. * * @param inbuf the input data * @return the hash output */ byte[] digest(byte[] inbuf); /** * Finalize the current hash computation and store the hash value * in the provided output buffer. The {@code len} parameter * contains the maximum number of bytes that should be written; * no more bytes than the natural hash function output length will * be produced. If {@code len} is smaller than the natural * hash output length, the hash output is truncated to its first * {@code len} bytes. The object is resetted. * * @param outbuf the output buffer * @param off the output offset within {@code outbuf} * @param len the requested hash output length (in bytes) * @return the number of bytes actually written in {@code outbuf} */ int digest(byte[] outbuf, int off, int len); /** * Get the natural hash function output length (in bytes). * * @return the digest output length (in bytes) */ int getDigestLength(); /** * Reset the object: this makes it suitable for a new hash * computation. The current computation, if any, is discarded. */ void reset(); /** * Clone the current state. The returned object evolves independantly * of this object. * * @return the clone */ Digest copy(); /** * <p>Return the "block length" for the hash function. This * value is naturally defined for iterated hash functions * (Merkle-Damgard). It is used in HMAC (that's what the * <a href="http://tools.ietf.org/html/rfc2104" rel="nofollow">HMAC specification</a> * names the "{@code B}" parameter).</p> * * <p>If the function is "block-less" then this function may * return {@code -n} where {@code n} is an integer such that the * block length for HMAC ("{@code B}") will be inferred from the * key length, by selecting the smallest multiple of {@code n} * which is no smaller than the key length. For instance, for * the Fugue-xxx hash functions, this function returns -4: the * virtual block length B is the HMAC key length, rounded up to * the next multiple of 4.</p> * * @return the internal block length (in bytes), or {@code -n} */ int getBlockLength(); /** * <p>Get the display name for this function (e.g. {@code "SHA-1"} * for SHA-1).</p> * * @see Object */ String toString(); }  DigestEngine public abstract class DigestEngine implements Digest { /** * Reset the hash algorithm state. */ protected abstract void engineReset(); /** * Process one block of data. * * @param data the data block */ protected abstract void processBlock(byte[] data); /** * Perform the final padding and store the result in the * provided buffer. This method shall call {@link #flush} * and then {@link #update} with the appropriate padding * data in order to get the full input data. * * @param buf the output buffer * @param off the output offset */ protected abstract void doPadding(byte[] buf, int off); /** * This function is called at object creation time; the * implementation should use it to perform initialization tasks. * After this method is called, the implementation should be ready * to process data or meaningfully honour calls such as * {@link #getDigestLength} */ protected abstract void doInit(); private int digestLen, blockLen, inputLen; private byte[] inputBuf, outputBuf; private long blockCount; /** * Instantiate the engine. */ public DigestEngine() { doInit(); digestLen = getDigestLength(); blockLen = getInternalBlockLength(); inputBuf = new byte[blockLen]; outputBuf = new byte[digestLen]; inputLen = 0; blockCount = 0; } private void adjustDigestLen() { if (digestLen == 0) { digestLen = getDigestLength(); outputBuf = new byte[digestLen]; } } /** @see org.ethereum.crypto.cryptohash.Digest */ public byte[] digest() { adjustDigestLen(); byte[] result = new byte[digestLen]; digest(result, 0, digestLen); return result; } /** @see org.ethereum.crypto.cryptohash.Digest */ public byte[] digest(byte[] input) { update(input, 0, input.length); return digest(); } /** @see org.ethereum.crypto.cryptohash.Digest */ public int digest(byte[] buf, int offset, int len) { adjustDigestLen(); if (len >= digestLen) { doPadding(buf, offset); reset(); return digestLen; } else { doPadding(outputBuf, 0); System.arraycopy(outputBuf, 0, buf, offset, len); reset(); return len; } } /** @see org.ethereum.crypto.cryptohash.Digest */ public void reset() { engineReset(); inputLen = 0; blockCount = 0; } /** @see org.ethereum.crypto.cryptohash.Digest */ public void update(byte input) { inputBuf[inputLen ++] = (byte)input; if (inputLen == blockLen) { processBlock(inputBuf); blockCount ++; inputLen = 0; } } /** @see org.ethereum.crypto.cryptohash.Digest */ public void update(byte[] input) { update(input, 0, input.length); } /** @see org.ethereum.crypto.cryptohash.Digest */ public void update(byte[] input, int offset, int len) { while (len > 0) { int copyLen = blockLen - inputLen; if (copyLen > len) copyLen = len; System.arraycopy(input, offset, inputBuf, inputLen, copyLen); offset += copyLen; inputLen += copyLen; len -= copyLen; if (inputLen == blockLen) { processBlock(inputBuf); blockCount ++; inputLen = 0; } } } /** * Get the internal block length. This is the length (in * bytes) of the array which will be passed as parameter to * {@link #processBlock}. The default implementation of this * method calls {@link #getBlockLength} and returns the same * value. Overriding this method is useful when the advertised * block length (which is used, for instance, by HMAC) is * suboptimal with regards to internal buffering needs. * * @return the internal block length (in bytes) */ protected int getInternalBlockLength() { return getBlockLength(); } /** * Flush internal buffers, so that less than a block of data * may at most be upheld. * * @return the number of bytes still unprocessed after the flush */ protected final int flush() { return inputLen; } /** * Get a reference to an internal buffer with the same size * than a block. The contents of that buffer are defined only * immediately after a call to {@link #flush()}: if * {@link #flush()} return the value {@code n}, then the * first {@code n} bytes of the array returned by this method * are the {@code n} bytes of input data which are still * unprocessed. The values of the remaining bytes are * undefined and may be altered at will. * * @return a block-sized internal buffer */ protected final byte[] getBlockBuffer() { return inputBuf; } /** * Get the "block count": this is the number of times the * {@link #processBlock} method has been invoked for the * current hash operation. That counter is incremented * <em>after</em> the call to {@link #processBlock}. * * @return the block count */ protected long getBlockCount() { return blockCount; } /** * This function copies the internal buffering state to some * other instance of a class extending {@code DigestEngine}. * It returns a reference to the copy. This method is intended * to be called by the implementation of the {@link #copy} * method. * * @param dest the copy * @return the value {@code dest} */ protected Digest copyState(DigestEngine dest) { dest.inputLen = inputLen; dest.blockCount = blockCount; System.arraycopy(inputBuf, 0, dest.inputBuf, 0, inputBuf.length); adjustDigestLen(); dest.adjustDigestLen(); System.arraycopy(outputBuf, 0, dest.outputBuf, 0, outputBuf.length); return dest; } }  KeccakCore abstract class KeccakCore extends DigestEngine { KeccakCore() { } private long[] A; private byte[] tmpOut; private static final long[] RC = { 0x0000000000000001L, 0x0000000000008082L, 0x800000000000808AL, 0x8000000080008000L, 0x000000000000808BL, 0x0000000080000001L, 0x8000000080008081L, 0x8000000000008009L, 0x000000000000008AL, 0x0000000000000088L, 0x0000000080008009L, 0x000000008000000AL, 0x000000008000808BL, 0x800000000000008BL, 0x8000000000008089L, 0x8000000000008003L, 0x8000000000008002L, 0x8000000000000080L, 0x000000000000800AL, 0x800000008000000AL, 0x8000000080008081L, 0x8000000000008080L, 0x0000000080000001L, 0x8000000080008008L }; /** * Encode the 64-bit word {@code val} into the array * {@code buf} at offset {@code off}, in little-endian * convention (least significant byte first). * * @param val the value to encode * @param buf the destination buffer * @param off the destination offset */ private static void encodeLELong(long val, byte[] buf, int off) { buf[off + 0] = (byte)val; buf[off + 1] = (byte)(val >>> 8); buf[off + 2] = (byte)(val >>> 16); buf[off + 3] = (byte)(val >>> 24); buf[off + 4] = (byte)(val >>> 32); buf[off + 5] = (byte)(val >>> 40); buf[off + 6] = (byte)(val >>> 48); buf[off + 7] = (byte)(val >>> 56); } /** * Decode a 64-bit little-endian word from the array {@code buf} * at offset {@code off}. * * @param buf the source buffer * @param off the source offset * @return the decoded value */ private static long decodeLELong(byte[] buf, int off) { return (buf[off + 0] & 0xFFL) | ((buf[off + 1] & 0xFFL) << 8) | ((buf[off + 2] & 0xFFL) << 16) | ((buf[off + 3] & 0xFFL) << 24) | ((buf[off + 4] & 0xFFL) << 32) | ((buf[off + 5] & 0xFFL) << 40) | ((buf[off + 6] & 0xFFL) << 48) | ((buf[off + 7] & 0xFFL) << 56); } /** @see org.ethereum.crypto.cryptohash.DigestEngine */ protected void engineReset() { doReset(); } /** @see org.ethereum.crypto.cryptohash.DigestEngine */ protected void processBlock(byte[] data) { /* Input block */ for (int i = 0; i < data.length; i += 8) A[i >>> 3] ^= decodeLELong(data, i); long t0, t1, t2, t3, t4; long tt0, tt1, tt2, tt3, tt4; long t, kt; long c0, c1, c2, c3, c4, bnn; /* * Unrolling four rounds kills performance big time * on Intel x86 Core2, in both 32-bit and 64-bit modes * (less than 1 MB/s instead of 55 MB/s on x86-64). * Unrolling two rounds appears to be fine. */ for (int j = 0; j < 24; j += 2) { tt0 = A[ 1] ^ A[ 6]; tt1 = A[11] ^ A[16]; tt0 ^= A[21] ^ tt1; tt0 = (tt0 << 1) | (tt0 >>> 63); tt2 = A[ 4] ^ A[ 9]; tt3 = A[14] ^ A[19]; tt0 ^= A[24]; tt2 ^= tt3; t0 = tt0 ^ tt2; tt0 = A[ 2] ^ A[ 7]; tt1 = A[12] ^ A[17]; tt0 ^= A[22] ^ tt1; tt0 = (tt0 << 1) | (tt0 >>> 63); tt2 = A[ 0] ^ A[ 5]; tt3 = A[10] ^ A[15]; tt0 ^= A[20]; tt2 ^= tt3; t1 = tt0 ^ tt2; tt0 = A[ 3] ^ A[ 8]; tt1 = A[13] ^ A[18]; tt0 ^= A[23] ^ tt1; tt0 = (tt0 << 1) | (tt0 >>> 63); tt2 = A[ 1] ^ A[ 6]; tt3 = A[11] ^ A[16]; tt0 ^= A[21]; tt2 ^= tt3; t2 = tt0 ^ tt2; tt0 = A[ 4] ^ A[ 9]; tt1 = A[14] ^ A[19]; tt0 ^= A[24] ^ tt1; tt0 = (tt0 << 1) | (tt0 >>> 63); tt2 = A[ 2] ^ A[ 7]; tt3 = A[12] ^ A[17]; tt0 ^= A[22]; tt2 ^= tt3; t3 = tt0 ^ tt2; tt0 = A[ 0] ^ A[ 5]; tt1 = A[10] ^ A[15]; tt0 ^= A[20] ^ tt1; tt0 = (tt0 << 1) | (tt0 >>> 63); tt2 = A[ 3] ^ A[ 8]; tt3 = A[13] ^ A[18]; tt0 ^= A[23]; tt2 ^= tt3; t4 = tt0 ^ tt2; A[ 0] = A[ 0] ^ t0; A[ 5] = A[ 5] ^ t0; A[10] = A[10] ^ t0; A[15] = A[15] ^ t0; A[20] = A[20] ^ t0; A[ 1] = A[ 1] ^ t1; A[ 6] = A[ 6] ^ t1; A[11] = A[11] ^ t1; A[16] = A[16] ^ t1; A[21] = A[21] ^ t1; A[ 2] = A[ 2] ^ t2; A[ 7] = A[ 7] ^ t2; A[12] = A[12] ^ t2; A[17] = A[17] ^ t2; A[22] = A[22] ^ t2; A[ 3] = A[ 3] ^ t3; A[ 8] = A[ 8] ^ t3; A[13] = A[13] ^ t3; A[18] = A[18] ^ t3; A[23] = A[23] ^ t3; A[ 4] = A[ 4] ^ t4; A[ 9] = A[ 9] ^ t4; A[14] = A[14] ^ t4; A[19] = A[19] ^ t4; A[24] = A[24] ^ t4; A[ 5] = (A[ 5] << 36) | (A[ 5] >>> (64 - 36)); A[10] = (A[10] << 3) | (A[10] >>> (64 - 3)); A[15] = (A[15] << 41) | (A[15] >>> (64 - 41)); A[20] = (A[20] << 18) | (A[20] >>> (64 - 18)); A[ 1] = (A[ 1] << 1) | (A[ 1] >>> (64 - 1)); A[ 6] = (A[ 6] << 44) | (A[ 6] >>> (64 - 44)); A[11] = (A[11] << 10) | (A[11] >>> (64 - 10)); A[16] = (A[16] << 45) | (A[16] >>> (64 - 45)); A[21] = (A[21] << 2) | (A[21] >>> (64 - 2)); A[ 2] = (A[ 2] << 62) | (A[ 2] >>> (64 - 62)); A[ 7] = (A[ 7] << 6) | (A[ 7] >>> (64 - 6)); A[12] = (A[12] << 43) | (A[12] >>> (64 - 43)); A[17] = (A[17] << 15) | (A[17] >>> (64 - 15)); A[22] = (A[22] << 61) | (A[22] >>> (64 - 61)); A[ 3] = (A[ 3] << 28) | (A[ 3] >>> (64 - 28)); A[ 8] = (A[ 8] << 55) | (A[ 8] >>> (64 - 55)); A[13] = (A[13] << 25) | (A[13] >>> (64 - 25)); A[18] = (A[18] << 21) | (A[18] >>> (64 - 21)); A[23] = (A[23] << 56) | (A[23] >>> (64 - 56)); A[ 4] = (A[ 4] << 27) | (A[ 4] >>> (64 - 27)); A[ 9] = (A[ 9] << 20) | (A[ 9] >>> (64 - 20)); A[14] = (A[14] << 39) | (A[14] >>> (64 - 39)); A[19] = (A[19] << 8) | (A[19] >>> (64 - 8)); A[24] = (A[24] << 14) | (A[24] >>> (64 - 14)); bnn = ~A[12]; kt = A[ 6] | A[12]; c0 = A[ 0] ^ kt; kt = bnn | A[18]; c1 = A[ 6] ^ kt; kt = A[18] & A[24]; c2 = A[12] ^ kt; kt = A[24] | A[ 0]; c3 = A[18] ^ kt; kt = A[ 0] & A[ 6]; c4 = A[24] ^ kt; A[ 0] = c0; A[ 6] = c1; A[12] = c2; A[18] = c3; A[24] = c4; bnn = ~A[22]; kt = A[ 9] | A[10]; c0 = A[ 3] ^ kt; kt = A[10] & A[16]; c1 = A[ 9] ^ kt; kt = A[16] | bnn; c2 = A[10] ^ kt; kt = A[22] | A[ 3]; c3 = A[16] ^ kt; kt = A[ 3] & A[ 9]; c4 = A[22] ^ kt; A[ 3] = c0; A[ 9] = c1; A[10] = c2; A[16] = c3; A[22] = c4; bnn = ~A[19]; kt = A[ 7] | A[13]; c0 = A[ 1] ^ kt; kt = A[13] & A[19]; c1 = A[ 7] ^ kt; kt = bnn & A[20]; c2 = A[13] ^ kt; kt = A[20] | A[ 1]; c3 = bnn ^ kt; kt = A[ 1] & A[ 7]; c4 = A[20] ^ kt; A[ 1] = c0; A[ 7] = c1; A[13] = c2; A[19] = c3; A[20] = c4; bnn = ~A[17]; kt = A[ 5] & A[11]; c0 = A[ 4] ^ kt; kt = A[11] | A[17]; c1 = A[ 5] ^ kt; kt = bnn | A[23]; c2 = A[11] ^ kt; kt = A[23] & A[ 4]; c3 = bnn ^ kt; kt = A[ 4] | A[ 5]; c4 = A[23] ^ kt; A[ 4] = c0; A[ 5] = c1; A[11] = c2; A[17] = c3; A[23] = c4; bnn = ~A[ 8]; kt = bnn & A[14]; c0 = A[ 2] ^ kt; kt = A[14] | A[15]; c1 = bnn ^ kt; kt = A[15] & A[21]; c2 = A[14] ^ kt; kt = A[21] | A[ 2]; c3 = A[15] ^ kt; kt = A[ 2] & A[ 8]; c4 = A[21] ^ kt; A[ 2] = c0; A[ 8] = c1; A[14] = c2; A[15] = c3; A[21] = c4; A[ 0] = A[ 0] ^ RC[j + 0]; tt0 = A[ 6] ^ A[ 9]; tt1 = A[ 7] ^ A[ 5]; tt0 ^= A[ 8] ^ tt1; tt0 = (tt0 << 1) | (tt0 >>> 63); tt2 = A[24] ^ A[22]; tt3 = A[20] ^ A[23]; tt0 ^= A[21]; tt2 ^= tt3; t0 = tt0 ^ tt2; tt0 = A[12] ^ A[10]; tt1 = A[13] ^ A[11]; tt0 ^= A[14] ^ tt1; tt0 = (tt0 << 1) | (tt0 >>> 63); tt2 = A[ 0] ^ A[ 3]; tt3 = A[ 1] ^ A[ 4]; tt0 ^= A[ 2]; tt2 ^= tt3; t1 = tt0 ^ tt2; tt0 = A[18] ^ A[16]; tt1 = A[19] ^ A[17]; tt0 ^= A[15] ^ tt1; tt0 = (tt0 << 1) | (tt0 >>> 63); tt2 = A[ 6] ^ A[ 9]; tt3 = A[ 7] ^ A[ 5]; tt0 ^= A[ 8]; tt2 ^= tt3; t2 = tt0 ^ tt2; tt0 = A[24] ^ A[22]; tt1 = A[20] ^ A[23]; tt0 ^= A[21] ^ tt1; tt0 = (tt0 << 1) | (tt0 >>> 63); tt2 = A[12] ^ A[10]; tt3 = A[13] ^ A[11]; tt0 ^= A[14]; tt2 ^= tt3; t3 = tt0 ^ tt2; tt0 = A[ 0] ^ A[ 3]; tt1 = A[ 1] ^ A[ 4]; tt0 ^= A[ 2] ^ tt1; tt0 = (tt0 << 1) | (tt0 >>> 63); tt2 = A[18] ^ A[16]; tt3 = A[19] ^ A[17]; tt0 ^= A[15]; tt2 ^= tt3; t4 = tt0 ^ tt2; A[ 0] = A[ 0] ^ t0; A[ 3] = A[ 3] ^ t0; A[ 1] = A[ 1] ^ t0; A[ 4] = A[ 4] ^ t0; A[ 2] = A[ 2] ^ t0; A[ 6] = A[ 6] ^ t1; A[ 9] = A[ 9] ^ t1; A[ 7] = A[ 7] ^ t1; A[ 5] = A[ 5] ^ t1; A[ 8] = A[ 8] ^ t1; A[12] = A[12] ^ t2; A[10] = A[10] ^ t2; A[13] = A[13] ^ t2; A[11] = A[11] ^ t2; A[14] = A[14] ^ t2; A[18] = A[18] ^ t3; A[16] = A[16] ^ t3; A[19] = A[19] ^ t3; A[17] = A[17] ^ t3; A[15] = A[15] ^ t3; A[24] = A[24] ^ t4; A[22] = A[22] ^ t4; A[20] = A[20] ^ t4; A[23] = A[23] ^ t4; A[21] = A[21] ^ t4; A[ 3] = (A[ 3] << 36) | (A[ 3] >>> (64 - 36)); A[ 1] = (A[ 1] << 3) | (A[ 1] >>> (64 - 3)); A[ 4] = (A[ 4] << 41) | (A[ 4] >>> (64 - 41)); A[ 2] = (A[ 2] << 18) | (A[ 2] >>> (64 - 18)); A[ 6] = (A[ 6] << 1) | (A[ 6] >>> (64 - 1)); A[ 9] = (A[ 9] << 44) | (A[ 9] >>> (64 - 44)); A[ 7] = (A[ 7] << 10) | (A[ 7] >>> (64 - 10)); A[ 5] = (A[ 5] << 45) | (A[ 5] >>> (64 - 45)); A[ 8] = (A[ 8] << 2) | (A[ 8] >>> (64 - 2)); A[12] = (A[12] << 62) | (A[12] >>> (64 - 62)); A[10] = (A[10] << 6) | (A[10] >>> (64 - 6)); A[13] = (A[13] << 43) | (A[13] >>> (64 - 43)); A[11] = (A[11] << 15) | (A[11] >>> (64 - 15)); A[14] = (A[14] << 61) | (A[14] >>> (64 - 61)); A[18] = (A[18] << 28) | (A[18] >>> (64 - 28)); A[16] = (A[16] << 55) | (A[16] >>> (64 - 55)); A[19] = (A[19] << 25) | (A[19] >>> (64 - 25)); A[17] = (A[17] << 21) | (A[17] >>> (64 - 21)); A[15] = (A[15] << 56) | (A[15] >>> (64 - 56)); A[24] = (A[24] << 27) | (A[24] >>> (64 - 27)); A[22] = (A[22] << 20) | (A[22] >>> (64 - 20)); A[20] = (A[20] << 39) | (A[20] >>> (64 - 39)); A[23] = (A[23] << 8) | (A[23] >>> (64 - 8)); A[21] = (A[21] << 14) | (A[21] >>> (64 - 14)); bnn = ~A[13]; kt = A[ 9] | A[13]; c0 = A[ 0] ^ kt; kt = bnn | A[17]; c1 = A[ 9] ^ kt; kt = A[17] & A[21]; c2 = A[13] ^ kt; kt = A[21] | A[ 0]; c3 = A[17] ^ kt; kt = A[ 0] & A[ 9]; c4 = A[21] ^ kt; A[ 0] = c0; A[ 9] = c1; A[13] = c2; A[17] = c3; A[21] = c4; bnn = ~A[14]; kt = A[22] | A[ 1]; c0 = A[18] ^ kt; kt = A[ 1] & A[ 5]; c1 = A[22] ^ kt; kt = A[ 5] | bnn; c2 = A[ 1] ^ kt; kt = A[14] | A[18]; c3 = A[ 5] ^ kt; kt = A[18] & A[22]; c4 = A[14] ^ kt; A[18] = c0; A[22] = c1; A[ 1] = c2; A[ 5] = c3; A[14] = c4; bnn = ~A[23]; kt = A[10] | A[19]; c0 = A[ 6] ^ kt; kt = A[19] & A[23]; c1 = A[10] ^ kt; kt = bnn & A[ 2]; c2 = A[19] ^ kt; kt = A[ 2] | A[ 6]; c3 = bnn ^ kt; kt = A[ 6] & A[10]; c4 = A[ 2] ^ kt; A[ 6] = c0; A[10] = c1; A[19] = c2; A[23] = c3; A[ 2] = c4; bnn = ~A[11]; kt = A[ 3] & A[ 7]; c0 = A[24] ^ kt; kt = A[ 7] | A[11]; c1 = A[ 3] ^ kt; kt = bnn | A[15]; c2 = A[ 7] ^ kt; kt = A[15] & A[24]; c3 = bnn ^ kt; kt = A[24] | A[ 3]; c4 = A[15] ^ kt; A[24] = c0; A[ 3] = c1; A[ 7] = c2; A[11] = c3; A[15] = c4; bnn = ~A[16]; kt = bnn & A[20]; c0 = A[12] ^ kt; kt = A[20] | A[ 4]; c1 = bnn ^ kt; kt = A[ 4] & A[ 8]; c2 = A[20] ^ kt; kt = A[ 8] | A[12]; c3 = A[ 4] ^ kt; kt = A[12] & A[16]; c4 = A[ 8] ^ kt; A[12] = c0; A[16] = c1; A[20] = c2; A[ 4] = c3; A[ 8] = c4; A[ 0] = A[ 0] ^ RC[j + 1]; t = A[ 5]; A[ 5] = A[18]; A[18] = A[11]; A[11] = A[10]; A[10] = A[ 6]; A[ 6] = A[22]; A[22] = A[20]; A[20] = A[12]; A[12] = A[19]; A[19] = A[15]; A[15] = A[24]; A[24] = A[ 8]; A[ 8] = t; t = A[ 1]; A[ 1] = A[ 9]; A[ 9] = A[14]; A[14] = A[ 2]; A[ 2] = A[13]; A[13] = A[23]; A[23] = A[ 4]; A[ 4] = A[21]; A[21] = A[16]; A[16] = A[ 3]; A[ 3] = A[17]; A[17] = A[ 7]; A[ 7] = t; } } /** @see org.ethereum.crypto.cryptohash.DigestEngine */ protected void doPadding(byte[] out, int off) { int ptr = flush(); byte[] buf = getBlockBuffer(); if ((ptr + 1) == buf.length) { buf[ptr] = (byte)0x81; } else { buf[ptr] = (byte)0x01; for (int i = ptr + 1; i < (buf.length - 1); i ++) buf[i] = 0; buf[buf.length - 1] = (byte)0x80; } processBlock(buf); A[ 1] = ~A[ 1]; A[ 2] = ~A[ 2]; A[ 8] = ~A[ 8]; A[12] = ~A[12]; A[17] = ~A[17]; A[20] = ~A[20]; int dlen = getDigestLength(); for (int i = 0; i < dlen; i += 8) encodeLELong(A[i >>> 3], tmpOut, i); System.arraycopy(tmpOut, 0, out, off, dlen); } /** @see org.ethereum.crypto.cryptohash.DigestEngine */ protected void doInit() { A = new long[25]; tmpOut = new byte[(getDigestLength() + 7) & ~7]; doReset(); } /** @see org.ethereum.crypto.cryptohash.Digest */ public int getBlockLength() { return 200 - 2 * getDigestLength(); } private final void doReset() { for (int i = 0; i < 25; i ++) A[i] = 0; A[ 1] = 0xFFFFFFFFFFFFFFFFL; A[ 2] = 0xFFFFFFFFFFFFFFFFL; A[ 8] = 0xFFFFFFFFFFFFFFFFL; A[12] = 0xFFFFFFFFFFFFFFFFL; A[17] = 0xFFFFFFFFFFFFFFFFL; A[20] = 0xFFFFFFFFFFFFFFFFL; } /** @see org.ethereum.crypto.cryptohash.DigestEngine */ protected Digest copyState(KeccakCore dst) { System.arraycopy(A, 0, dst.A, 0, 25); return super.copyState(dst); } /** @see org.ethereum.crypto.cryptohash.Digest */ public String toString() { return "Keccak-" + (getDigestLength() << 3); } }  Keccak256 public class Keccak256 extends KeccakCore { /** * Create the engine. */ public Keccak256() { } /** @see org.ethereum.crypto.cryptohash.Digest */ public Digest copy() { return copyState(new Keccak256()); } /** @see org.ethereum.crypto.cryptohash.Digest */ public int getDigestLength() { return 32; } }  Keccak512 public class Keccak512 extends KeccakCore { /** * Create the engine. */ public Keccak512() { } /** @see Digest */ public Digest copy() { return copyState(new Keccak512()); } /** @see Digest */ public int getDigestLength() { return 64; } }   测试代码 public static byte[] sha3(byte[] input) { Keccak256 digest = new Keccak256(); digest.update(input); return digest.digest(); } @Test public void test() { String message = "13120983870"; byte[] result = sha3(message.getBytes()); System.out.println("base64:" + Base64.byteArrayToBase64(result)); }   运行结果 base64:MFs2drA5BkHW8/hhU4xzNzdA/E/ySpvAJ1iypI+Cyhs=              

已有 0 人发表留言,猛击->>这里<<-参与讨论


ITeye推荐



]]>
Wed, 16 Jan 2019 00:16:34 +0800 https://lobin.iteye.com/blog/2436668 https://lobin.iteye.com/blog/2436668
ITeye Java编程 Spring框架 Ajax技术 agile敏捷软件开发 ruby on rails实践 - ITeye做最棒的软件开发交流社区 - 乐虎国际|授权平台  EncodedKeySpec java.security.spec.EncodedKeySpec   PKCS8EncodedKeySpec 私钥的ASN.1编码(规范),编码按照PKCS#8标准:   PrivateKeyInfo ::= SEQUENCE { version Version, privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, privateKey PrivateKey, attributes [0] IMPLICIT Attributes OPTIONAL } Version ::= INTEGER PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier PrivateKey ::= OCTET STRING Attributes ::= SET OF Attribute     X509EncodedKeySpec 公钥的ASN.1编码(规范),编码按照X.509标准:   SubjectPublicKeyInfo ::= SEQUENCE { algorithm AlgorithmIdentifier, subjectPublicKey BIT STRING }     String privateKey = "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEApTHMs+zR16SE0v3npoVbMGo70xX5tJ7HF23SvM2rARkJNtRs4xZRQpWQ1JBZnGna9HcVQsrRAORqYhhTrZ9rMQIDAQABAkAFNrlYrasZErJGQEEiIWP9lwHCvZchLTB4j+TahIV+2iLTiLa21QOqQFmpBqw/uqmHsJGtqtHIXdtgCrGtoLVhAiEA4zpbZ52vkCskvZ2eJ34n6dTsiybZLIMYIdp21kd6mpECIQC6HJ2f0R6BwL/ORYhF6tA1YeXZEKyAuTgDkwgmGN/WoQIgPsXrZHeafbB9iOiXPX/LlPyekF6eFn7s1sVcmRvMEhECIBnJDS2vU4K2qdxyVccaGW7L+YRxgvTytIgKPv7IQ3sBAiEAh3XrxyuR3nJhFD5pPcRLmnst9Ag6WQuthc/SgkKJlXk="; String publicKey = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKUxzLPs0dekhNL956aFWzBqO9MV+bSexxdt0rzNqwEZCTbUbOMWUUKVkNSQWZxp2vR3FULK0QDkamIYU62fazECAwEAAQ=="; byte[] privateKeyEncoded = Base64.base64ToByteArray(privateKey); byte[] publicKeyEncoded = Base64.base64ToByteArray(publicKey);   // 加密 PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKeyEncoded); KeyFactory keyFactory = null; try { keyFactory = KeyFactory.getInstance("RSA"); } catch (NoSuchAlgorithmException e) { Assert.fail("no such algorithm: " + e.getMessage()); } PrivateKey privateKey = null; try { privateKey = keyFactory.generatePrivate(pkcs8KeySpec); } catch (InvalidKeySpecException e) { Assert.fail("invalid key spec: " + e.getMessage()); } System.out.println("private key: " + Base64.byteArrayToBase64(((Key) privateKey).getEncoded()));   // 解密 X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKeyEncoded); try { keyFactory = KeyFactory.getInstance("RSA"); } catch (NoSuchAlgorithmException e) { Assert.fail("no such algorithm: " + e.getMessage()); } PublicKey publicKey = null; try { publicKey = keyFactory.generatePublic(x509KeySpec); } catch (InvalidKeySpecException e) { Assert.fail("invalid key spec: " + e.getMessage()); } System.out.println("public key: " + Base64.byteArrayToBase64(((Key) publicKey).getEncoded()));   完整代码 /** * private key: MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEApTHMs+zR16SE0v3npoVbMGo70xX5tJ7HF23SvM2rARkJNtRs4xZRQpWQ1JBZnGna9HcVQsrRAORqYhhTrZ9rMQIDAQABAkAFNrlYrasZErJGQEEiIWP9lwHCvZchLTB4j+TahIV+2iLTiLa21QOqQFmpBqw/uqmHsJGtqtHIXdtgCrGtoLVhAiEA4zpbZ52vkCskvZ2eJ34n6dTsiybZLIMYIdp21kd6mpECIQC6HJ2f0R6BwL/ORYhF6tA1YeXZEKyAuTgDkwgmGN/WoQIgPsXrZHeafbB9iOiXPX/LlPyekF6eFn7s1sVcmRvMEhECIBnJDS2vU4K2qdxyVccaGW7L+YRxgvTytIgKPv7IQ3sBAiEAh3XrxyuR3nJhFD5pPcRLmnst9Ag6WQuthc/SgkKJlXk= * public key: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKUxzLPs0dekhNL956aFWzBqO9MV+bSexxdt0rzNqwEZCTbUbOMWUUKVkNSQWZxp2vR3FULK0QDkamIYU62fazECAwEAAQ== */ @Test public void test11() { String privateKey = "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEApTHMs+zR16SE0v3npoVbMGo70xX5tJ7HF23SvM2rARkJNtRs4xZRQpWQ1JBZnGna9HcVQsrRAORqYhhTrZ9rMQIDAQABAkAFNrlYrasZErJGQEEiIWP9lwHCvZchLTB4j+TahIV+2iLTiLa21QOqQFmpBqw/uqmHsJGtqtHIXdtgCrGtoLVhAiEA4zpbZ52vkCskvZ2eJ34n6dTsiybZLIMYIdp21kd6mpECIQC6HJ2f0R6BwL/ORYhF6tA1YeXZEKyAuTgDkwgmGN/WoQIgPsXrZHeafbB9iOiXPX/LlPyekF6eFn7s1sVcmRvMEhECIBnJDS2vU4K2qdxyVccaGW7L+YRxgvTytIgKPv7IQ3sBAiEAh3XrxyuR3nJhFD5pPcRLmnst9Ag6WQuthc/SgkKJlXk="; String publicKey = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKUxzLPs0dekhNL956aFWzBqO9MV+bSexxdt0rzNqwEZCTbUbOMWUUKVkNSQWZxp2vR3FULK0QDkamIYU62fazECAwEAAQ=="; byte[] privateKeyEncoded = Base64.base64ToByteArray(privateKey); byte[] publicKeyEncoded = Base64.base64ToByteArray(publicKey); String message = "13120983870"; System.out.println(message); encryptAndDecrypt(message, privateKeyEncoded, publicKeyEncoded); }   private void encryptAndDecrypt(String message, byte[] privateKeyEncoded, byte[] publicKeyEncoded) { // 加密 PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKeyEncoded); KeyFactory keyFactory = null; try { keyFactory = KeyFactory.getInstance("RSA"); } catch (NoSuchAlgorithmException e) { Assert.fail("no such algorithm: " + e.getMessage()); } PrivateKey privateKey = null; try { privateKey = keyFactory.generatePrivate(pkcs8KeySpec); } catch (InvalidKeySpecException e) { Assert.fail("invalid key spec: " + e.getMessage()); } System.out.println("private key: " + Base64.byteArrayToBase64(((Key) privateKey).getEncoded())); Cipher cipher = null; try { cipher = Cipher.getInstance(keyFactory.getAlgorithm()); } catch (NoSuchAlgorithmException e) { Assert.fail("no such algorithm: " + e.getMessage()); } catch (NoSuchPaddingException e) { Assert.fail("no such padding: " + e.getMessage()); } try { cipher.init(Cipher.ENCRYPT_MODE, privateKey); } catch (InvalidKeyException e) { Assert.fail("invalid key: " + e.getMessage()); } byte[] encryption = null; try { encryption = cipher.doFinal(message.getBytes()); } catch (IllegalBlockSizeException e) { Assert.fail("illegal block size: " + e.getMessage()); } catch (BadPaddingException e) { Assert.fail("bad padding: " + e.getMessage()); } System.out.println("encryption: " + Base64.byteArrayToBase64(encryption)); // 解密 X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKeyEncoded); try { keyFactory = KeyFactory.getInstance("RSA"); } catch (NoSuchAlgorithmException e) { Assert.fail("no such algorithm: " + e.getMessage()); } PublicKey publicKey = null; try { publicKey = keyFactory.generatePublic(x509KeySpec); } catch (InvalidKeySpecException e) { Assert.fail("invalid key spec: " + e.getMessage()); } System.out.println("public key: " + Base64.byteArrayToBase64(((Key) publicKey).getEncoded())); try { cipher = Cipher.getInstance(keyFactory.getAlgorithm()); } catch (NoSuchAlgorithmException e) { Assert.fail("no such algorithm: " + e.getMessage()); } catch (NoSuchPaddingException e) { Assert.fail("no such padding: " + e.getMessage()); } try { cipher.init(Cipher.DECRYPT_MODE, publicKey); } catch (InvalidKeyException e) { Assert.fail("invalid key: " + e.getMessage()); } byte[] decryption = null; try { decryption = cipher.doFinal(encryption); } catch (IllegalBlockSizeException e) { Assert.fail("illegal block size: " + e.getMessage()); } catch (BadPaddingException e) { Assert.fail("bad padding: " + e.getMessage()); } System.out.println("decryption: " + new String(decryption) + ", base64:" + Base64.byteArrayToBase64(decryption)); }          

已有 0 人发表留言,猛击->>这里<<-参与讨论


ITeye推荐



]]>
Tue, 15 Jan 2019 22:17:20 +0800 https://lobin.iteye.com/blog/2436665 https://lobin.iteye.com/blog/2436665