result = new HashMap<>( 2 );
+ result.put( "key", key );
+ result.put( "content", Base64Utils.encode( encryptedBytes ) );
+ return result;
+ }
+ catch ( Exception e )
+ {
+ throw new RuntimeException( "加密失败:" + e.getMessage(), e );
+ }
+ }
+
+ /**
+ * 解密
+ *
+ * @param key
+ * @param privateKey
+ * @param content
+ * @return
+ */
+ public static String decryptData( String key, String privateKey, String content )
+ {
+ try
+ {
+ System.out.println( "KEY:" + key );
+ System.out.println( "privateKey:" + privateKey );
+ System.out.println( "content:" + content );
+ // base64 解码
+ byte[] encryptedBytes = Base64Utils.decode( content );
+ key = RSAUtils.decryptByPrivateKey( privateKey, key );
+ byte[] enCodeFormat = key.getBytes();
+ SecretKeySpec secretKey = new SecretKeySpec( enCodeFormat, "AES" );
+ byte[] initParam = IV_STRING.getBytes();
+ IvParameterSpec ivParameterSpec = new IvParameterSpec( initParam );
+ Cipher cipher = Cipher.getInstance( "AES/CBC/PKCS5Padding" );
+ cipher.init( Cipher.DECRYPT_MODE, secretKey, ivParameterSpec );
+ byte[] result = cipher.doFinal( encryptedBytes );
+ return new String( result, "UTF-8" );
+ }
+ catch ( Exception e )
+ {
+ throw new RuntimeException( "解密失败:" + e.getMessage(), e );
+ }
+ }
+
+}
diff --git a/code/cpicxim-huixiabao/src/main/java/com/cpic/xim/utils/secrecy/Base64Utils.java b/code/cpicxim-huixiabao/src/main/java/com/cpic/xim/utils/secrecy/Base64Utils.java
new file mode 100644
index 0000000..8ae7e8e
--- /dev/null
+++ b/code/cpicxim-huixiabao/src/main/java/com/cpic/xim/utils/secrecy/Base64Utils.java
@@ -0,0 +1,164 @@
+/*
+ * @Author: Kane
+ * @Date: 2025-03-15 12:04:19
+ * @LastEditors: Kane
+ * @FilePath: /cpicxim-huixiabao/src/main/java/com/cpic/xim/utils/secrecy/Base64Utils.java
+ * @Description:
+ *
+ * Copyright (c) ${2023} by Kane, All Rights Reserved.
+ */
+package com.cpic.xim.utils.secrecy;
+
+import org.apache.commons.codec.binary.Base64;
+import java.io.*;
+
+/**
+ * Base64Utils
+ */
+public class Base64Utils
+{
+
+ /** */
+ /**
+ * 文件读取缓冲区大小
+ */
+ private static final int CACHE_SIZE = 1024;
+
+ /** */
+ /**
+ *
+ * BASE64字符串解码为二进制数据
+ *
+ *
+ * @param base64
+ * @return
+ * @throws Exception
+ */
+ public static byte[] decode( String base64 )
+ throws Exception
+ {
+ return Base64.decodeBase64( base64.getBytes() );
+ }
+
+ public static String decode( byte[] b )
+ throws Exception
+ {
+ return new String( Base64.decodeBase64( b ) );
+ }
+
+ /** */
+ /**
+ *
+ * 二进制数据编码为BASE64字符串
+ *
+ *
+ * @param bytes
+ * @return
+ */
+ public static String encode( byte[] bytes )
+ {
+ return new String( Base64.encodeBase64( bytes ) );
+ }
+
+ /** */
+ /**
+ *
+ * 将文件编码为BASE64字符串
+ *
+ *
+ * 大文件慎用,可能会导致内存溢出
+ *
+ *
+ * @param filePath 文件绝对路径
+ * @return
+ * @throws Exception
+ */
+ public static String encodeFile( String filePath )
+ throws Exception
+ {
+ byte[] bytes = fileToByte( filePath );
+ return encode( bytes );
+ }
+
+ /** */
+ /**
+ *
+ * BASE64字符串转回文件
+ *
+ *
+ * @param filePath 文件绝对路径
+ * @param base64 编码字符串
+ * @throws Exception
+ */
+ public static void decodeToFile( String filePath, String base64 )
+ throws Exception
+ {
+ byte[] bytes = decode( base64 );
+ byteArrayToFile( bytes, filePath );
+ }
+
+ /** */
+ /**
+ *
+ * 文件转换为二进制数组
+ *
+ *
+ * @param filePath 文件路径
+ * @return
+ * @throws Exception
+ */
+ public static byte[] fileToByte( String filePath )
+ throws Exception
+ {
+ byte[] data = new byte[0];
+ File file = new File( filePath );
+ if ( file.exists() )
+ {
+ FileInputStream in = new FileInputStream( file );
+ ByteArrayOutputStream out = new ByteArrayOutputStream( 2048 );
+ byte[] cache = new byte[CACHE_SIZE];
+ int nRead = 0;
+ while ( (nRead = in.read( cache )) != -1 )
+ {
+ out.write( cache, 0, nRead );
+ out.flush();
+ }
+ out.close();
+ in.close();
+ data = out.toByteArray();
+ }
+ return data;
+ }
+
+ /** */
+ /**
+ *
+ * 二进制数据写文件
+ *
+ *
+ * @param bytes 二进制数据
+ * @param filePath 文件生成目录
+ */
+ public static void byteArrayToFile( byte[] bytes, String filePath )
+ throws Exception
+ {
+ InputStream in = new ByteArrayInputStream( bytes );
+ File destFile = new File( filePath );
+ if ( !destFile.getParentFile().exists() )
+ {
+ destFile.getParentFile().mkdirs();
+ }
+ destFile.createNewFile();
+ OutputStream out = new FileOutputStream( destFile );
+ byte[] cache = new byte[CACHE_SIZE];
+ int nRead = 0;
+ while ( (nRead = in.read( cache )) != -1 )
+ {
+ out.write( cache, 0, nRead );
+ out.flush();
+ }
+ out.close();
+ in.close();
+ }
+
+}
diff --git a/code/cpicxim-huixiabao/src/main/java/com/cpic/xim/utils/secrecy/RSAUtils.java b/code/cpicxim-huixiabao/src/main/java/com/cpic/xim/utils/secrecy/RSAUtils.java
new file mode 100644
index 0000000..8da1a96
--- /dev/null
+++ b/code/cpicxim-huixiabao/src/main/java/com/cpic/xim/utils/secrecy/RSAUtils.java
@@ -0,0 +1,169 @@
+package com.cpic.xim.utils.secrecy;
+
+import javax.crypto.Cipher;
+import java.io.ByteArrayOutputStream;
+import java.math.BigInteger;
+import java.security.*;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.RSAPrivateKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * RSAUtils
+ */
+public class RSAUtils {
+
+ /**
+ * RSA最大加密明文大小
+ */
+ private static final int MAX_ENCRYPT_BLOCK = 117;
+
+ /**
+ * RSA最大解密密文大小
+ */
+ private static final int MAX_DECRYPT_BLOCK = 128;
+
+ /**
+ * 加密算法RSA
+ */
+ private static final String KEY_ALGORITHM = "RSA";
+
+ /**
+ * 生成公钥和私钥
+ *
+ * @throws Exception
+ */
+ public static Map getKeys() throws Exception {
+ KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
+ keyPairGen.initialize(1024);
+ KeyPair keyPair = keyPairGen.generateKeyPair();
+ RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
+ RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
+
+ String publicKeyStr = getPublicKeyStr(publicKey);
+ String privateKeyStr = getPrivateKeyStr(privateKey);
+
+ Map result = new HashMap<>(2);
+ result.put("publicKeyStr", publicKeyStr);
+ result.put("privateKeyStr", privateKeyStr);
+
+ return result;
+ }
+
+ public static void main(String[] args) throws Exception {
+ Map keys = getKeys();
+ System.out.println("publicKeyStr=" + keys.get("publicKeyStr"));
+ System.out.println("privateKeyStr=" + keys.get("privateKeyStr"));
+ }
+
+ /**
+ * 使用模和指数生成RSA私钥
+ * 注意:【此代码用了默认补位方式,为RSA/None/PKCS1Padding,不同JDK默认的补位方式可能不同,如Android默认是RSA
+ * /None/NoPadding】
+ *
+ * @param modulus 模
+ * @param exponent 指数
+ * @return
+ */
+ public static RSAPrivateKey getPrivateKey(String modulus, String exponent) {
+ try {
+ BigInteger b1 = new BigInteger(modulus);
+ BigInteger b2 = new BigInteger(exponent);
+ KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+ RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(b1, b2);
+ return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * 公钥加密
+ *
+ * @param data 加密数据
+ * @param publicKey 加密key
+ * @return
+ * @throws Exception
+ */
+ public static String encryptByPublicKey(String data, String publicKey) throws Exception {
+ byte[] dataByte = data.getBytes();
+ byte[] keyBytes = Base64Utils.decode(publicKey);
+ X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
+ KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
+ Key publicK = keyFactory.generatePublic(x509KeySpec);
+ // 对数据加密
+ Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
+ cipher.init(Cipher.ENCRYPT_MODE, publicK);
+ int inputLen = dataByte.length;
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ int offSet = 0;
+ byte[] cache;
+ int i = 0;
+ // 对数据分段加密
+ while (inputLen - offSet > 0) {
+ if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
+ cache = cipher.doFinal(dataByte, offSet, MAX_ENCRYPT_BLOCK);
+ } else {
+ cache = cipher.doFinal(dataByte, offSet, inputLen - offSet);
+ }
+ out.write(cache, 0, cache.length);
+ i++;
+ offSet = i * MAX_ENCRYPT_BLOCK;
+ }
+ byte[] encryptedData = out.toByteArray();
+ out.close();
+ return Base64Utils.encode(encryptedData);
+ }
+
+ /**
+ * 私钥解密
+ *
+ * @param privateKey 私钥
+ * @param data 加密数据
+ * @return
+ * @throws Exception
+ */
+ public static String decryptByPrivateKey(String privateKey, String data) throws Exception {
+ byte[] encryptedData = Base64Utils.decode(data);
+ byte[] keyBytes = Base64Utils.decode(privateKey);
+ PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
+ KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
+ Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
+ // Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
+ Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
+
+ cipher.init(Cipher.DECRYPT_MODE, privateK);
+ int inputLen = encryptedData.length;
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ int offSet = 0;
+ byte[] cache;
+ int i = 0;
+ // 对数据分段解密
+ while (inputLen - offSet > 0) {
+ if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
+ cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
+ } else {
+ cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
+ }
+ out.write(cache, 0, cache.length);
+ i++;
+ offSet = i * MAX_DECRYPT_BLOCK;
+ }
+ byte[] decryptedData = out.toByteArray();
+ out.close();
+ return new String(decryptedData);
+ }
+
+ public static String getPrivateKeyStr(PrivateKey privateKey) {
+ return Base64Utils.encode(privateKey.getEncoded());
+ }
+
+ public static String getPublicKeyStr(PublicKey publicKey) {
+ return Base64Utils.encode(publicKey.getEncoded());
+ }
+}
\ No newline at end of file
diff --git a/code/cpicxim-huixiabao/src/main/webapp/WEB-INF/classes/spring.xml b/code/cpicxim-huixiabao/src/main/webapp/WEB-INF/classes/spring.xml
new file mode 100644
index 0000000..a349f68
--- /dev/null
+++ b/code/cpicxim-huixiabao/src/main/webapp/WEB-INF/classes/spring.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/code/cpicxim-huixiabao/src/main/webapp/WEB-INF/web.xml b/code/cpicxim-huixiabao/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..c7b2872
--- /dev/null
+++ b/code/cpicxim-huixiabao/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,25 @@
+
+
+ Archetype Created Web Application
+
+
+ springmvc
+ org.springframework.web.servlet.DispatcherServlet
+
+ contextConfigLocation
+ classpath:spring.xml
+
+ 1
+
+
+ springmvc
+ /huixibao
+
+
+
\ No newline at end of file
diff --git a/code/cpicxim-huixiabao/src/main/webapp/index.jsp b/code/cpicxim-huixiabao/src/main/webapp/index.jsp
new file mode 100644
index 0000000..ee89d62
--- /dev/null
+++ b/code/cpicxim-huixiabao/src/main/webapp/index.jsp
@@ -0,0 +1,5 @@
+
+
+<%= "Hello World!" %>
+
+