CentOS 8 安装 Apache Commons Crypto 指南
在 CentOS 8 服务器上从零搭建 Apache Commons Crypto 1.2.0 环境:dnf 安装 JDK 17 与 Maven、alternatives 多版本切换、openssl-devel 依赖与双方案获取实测。
CentOS 8 安装 Apache Commons Crypto 指南
目标:在 CentOS 8 服务器上从零搭建可编译、可运行 Apache Commons Crypto 1.2.0 的环境,覆盖 JDK 17 与 Maven 安装、JDK 多版本切换、OpenSSL 依赖补齐与两种 jar 获取方案,全部步骤已在 Ubuntu 22.04 / CentOS 8(JDK 17 + Maven)实测通过。
一、环境信息
本章先确认操作系统与基础软件版本,后续所有命令与回显均来自该环境。安装开始前,请先核对服务器系统版本:
grep PRETTY_NAME /etc/os-release && uname -r
回显(实测):
PRETTY_NAME="CentOS Linux 8"
6.8.0-138-generic
本文使用的环境基准如下:
| 项目 | 内容 |
|---|---|
| 操作系统 | CentOS Linux 8(x86_64,8.4.2105) |
| 内核 | 6.8.0-138-generic |
| JDK | OpenJDK 17.0.1(AppStream 仓库 java-17-openjdk-devel) |
| 构建工具 | Apache Maven 3.5.4(Red Hat 3.5.4-5) |
| OpenSSL | 1.1.1k FIPS 25 Mar 2021(系统默认 libcrypto.so.1.1) |
| 组件版本 | Apache Commons Crypto 1.2.0 |
CentOS 8 相比 Ubuntu 的两个关键差异会在后文反复出现:一是 AppStream 仓库里的 Maven 默认绑定了系统既有的 JDK 8,必须用 alternatives 与 JAVA_HOME 显式切到 17;二是 CentOS 8 的 OpenSSL 是 1.1.1k,恰好落在 Commons Crypto 1.2.0 JNI 代码完整支持的版本线上,加密与随机数都能走 OpenSSL 原生路径。
1.1 安装 JDK 17 与 Maven
CentOS 8 的 AppStream 仓库直接提供两个包,一条命令完成安装:
dnf install -y java-17-openjdk-devel maven
回显(实测,节选):
Installed:
maven-1:3.5.4-5.module_el8.0.0+39+6a9b6e22.noarch
java-17-openjdk-devel-1:17.0.1.0.12-2.el8_5.x86_64
Complete!
安装完成但还不能直接用:CentOS 8 服务器通常预装了 JDK 8,java 命令默认仍指向旧版本。用 alternatives 把 java 与 javac 都切到 17:
alternatives --set java java-17-openjdk.x86_64 && alternatives --set javac java-17-openjdk.x86_64
java -version
回显(实测):
openjdk version "17.0.1" 2021-10-19 LTS
OpenJDK Runtime Environment 21.9 (build 17.0.1+12-LTS)
OpenJDK 64-Bit Server VM 21.9 (build 17.0.1+12-LTS, mixed mode, sharing)
javac -version
回显(实测):
javac 17.0.1
1.2 Maven 的 JAVA_HOME 陷阱
这是 CentOS 8 特有的必踩坑:mvn 不是读 alternatives,而是读环境变量 JAVA_HOME。不设置时它继续用 JDK 8,编译 17 目标会直接失败:
mvn -version
回显(实测,未设置 JAVA_HOME 时):
Apache Maven 3.5.4 (Red Hat 3.5.4-5)
Maven home: /usr/share/maven
Java version: 1.8.0_312, vendor: Red Hat, Inc., runtime: /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.312.b07-2.el8_5.x86_64/jre
Default locale: en_US, platform encoding: ANSI_X3.4-1968
OS name: "linux", version: "6.8.0-138-generic", arch: "amd64", family: "unix"
把 JAVA_HOME 指向 JDK 17 后再验证:
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk
mvn -version
回显(实测):
Apache Maven 3.5.4 (Red Hat 3.5.4-5)
Maven home: /usr/share/maven
Java version: 17.0.1, vendor: Red Hat, Inc., runtime: /usr/lib/jvm/java-17-openjdk-17.0.1.0.12-2.el8_5.x86_64
建议把 export JAVA_HOME=/usr/lib/jvm/java-17-openjdk 写入 /etc/profile.d/jdk17.sh 或用户级 ~/.bashrc,避免每次登录重设。
1.3 确认 OpenSSL 运行库
Commons Crypto 的 native 路径需要系统提供 libcrypto。CentOS 8 自带 OpenSSL 1.1.1k:
openssl version
回显(实测):
OpenSSL 1.1.1k FIPS 25 Mar 2021
ldconfig -p | grep libcrypto
回显(实测):
libcrypto.so.1.1 (libc6,x86-64) => /lib64/libcrypto.so.1.1
默认只有带版本号的 libcrypto.so.1.1,而 Commons Crypto 运行时会 dlopen 未带版本号的 libcrypto.so。补装开发包生成符号链接:
dnf install -y openssl-devel
ldconfig -p | grep "libcrypto.so "
回显(实测):
libcrypto.so (libc6,x86-64) => /lib64/libcrypto.so
二、版本选型
选型前先明确 JDK 版本要求与 native 支持平台,以下信息均来自对 1.2.0 发行物的实测检查。
2.1 版本清单
| 版本 | 状态 | JDK 要求 | 说明 |
|---|---|---|---|
| 1.2.0 | 当前最新稳定版 | Java 8 及以上 | 2022-12-30 发布;实测 jar 内 class 文件 major version 为 52(即 Java 8 字节码),可在 JDK 8 至 17 上运行 |
| 1.1.0 | 旧稳定版 | Java 8 及以上 | 历史版本,可从 Apache 归档站点获取 |
| 1.0.0 | 旧稳定版 | Java 7 及以上 | 首个正式版,不建议新项目使用 |
选型建议:新项目直接使用 1.2.0。CentOS 8 的 OpenSSL 1.1.1 环境是 1.2.0 的最佳搭档——加密与随机数两条 native 路径都能完整生效,这是它与 Ubuntu 22.04(OpenSSL 3.0,加密回退 JCE)最大的差别。
💡 技术拓展:Commons Crypto 获取原生加解密能力有三条实现路径——JCE(JVM 自带软件实现,依赖 JVM 对 AES-NI 指令的优化)、OpenSSL JNI(jar 内自带各平台 JNI 胶水库,调用系统 OpenSSL 的 libcrypto)、JNA(通过 JNA 库调用 OpenSSL,无需编译 JNI 但吞吐较低,1.2.0 的 pom 中 jna 是编译期依赖,运行时作为可选路径)。本文环境实测:加密与随机数均选中 OpenSSL JNI 路径(OpenSslCipher 与 OpenSslCryptoRandom),与 JCE 路径产出的密文逐字节一致。
2.2 native 支持平台
1.2.0 的 jar 内自带多平台 JNI 胶水库(jar tf 实测清单):
| 平台 | 内嵌库路径(jar 内) |
|---|---|
| Linux x86_64 | org/apache/commons/crypto/native/Linux/x86_64/libcommons-crypto.so |
| Linux aarch64 | org/apache/commons/crypto/native/Linux/aarch64/libcommons-crypto.so |
| Linux arm | org/apache/commons/crypto/native/Linux/arm/libcommons-crypto.so |
| Linux armhf | org/apache/commons/crypto/native/Linux/armhf/libcommons-crypto.so |
| macOS x86_64 | org/apache/commons/crypto/native/Mac/x86_64/libcommons-crypto.jnilib |
| Windows x86 | org/apache/commons/crypto/native/Windows/x86/commons-crypto.dll |
| Windows x86_64 | org/apache/commons/crypto/native/Windows/x86_64/commons-crypto.dll |
逐项说明:x86_64 Linux 是本文环境;胶水库只是 JNI 桥,运行时仍需系统提供 libcrypto(OpenSSL),jar 并不内嵌 OpenSSL 本体,这就是 1.3 节补装 openssl-devel 的原因。
三、方案A:Maven 中央仓库依赖
方案A适合所有使用 Maven 的工程:pom 声明依赖即可,无需手工管理 jar。Maven 坐标为 org.apache.commons:commons-crypto:1.2.0。
3.1 创建工程与 pom
mkdir -p /opt/install-demo/src/main/java
创建 /opt/install-demo/pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>demo</groupId>
<artifactId>crypto-quickstart</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-crypto</artifactId>
<version>1.2.0</version>
</dependency>
</dependencies>
</project>
逐项说明:maven.compiler.source/target 设为 17 与本环境 JDK 匹配;project.build.sourceEncoding 强制 UTF-8,规避 POSIX locale 下的编译编码问题;依赖坐标只有 commons-crypto 一项。
3.2 编译并查看真实依赖树
如果跳过 1.2 节的 JAVA_HOME 设置,编译会在这一步失败(实测错误信息):
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (default-compile) on project crypto-quickstart: Fatal error compiling: invalid target release: 17
设置 JAVA_HOME 后再编译:
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk && cd /opt/install-demo && mvn -q compile && echo BUILD_OK
回显(实测):
BUILD_OK
mvn dependency:tree
回显(实测,节选):
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ crypto-quickstart ---
[INFO] demo:crypto-quickstart:jar:1.0.0
[INFO] \- org.apache.commons:commons-crypto:jar:1.2.0:compile
[INFO] +- net.java.dev.jna:jna:jar:5.13.0:compile
[INFO] \- com.sun.xml.bind:jaxb-impl:jar:2.3.7:compile
[INFO] +- jakarta.xml.bind:jakarta.xml.bind-api:jar:2.3.3:compile
[INFO] \- com.sun.activation:jakarta.activation:jar:1.2.2:runtime
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
依赖树解读:commons-crypto 1.2.0 的传递依赖只有 jna 5.13.0(对应可选 JNA 路径)与 jaxb-impl 2.3.7(来自 pom 中 JDK 11 及以上激活的 profile,用于在 JDK 11+ 上补齐 JAXB);jaxb-impl 再带入 jakarta.xml.bind-api 2.3.3 与 jakarta.activation 1.2.2。总体非常轻量。
3.3 最小验证代码
将以下内容保存为 /opt/install-demo/src/main/java/EnvCheck.java,打印组件版本、native 加载状态、各变换实际选用的实现类:
import org.apache.commons.crypto.Crypto;
import org.apache.commons.crypto.cipher.CryptoCipher;
import org.apache.commons.crypto.cipher.CryptoCipherFactory;
import org.apache.commons.crypto.random.CryptoRandom;
import org.apache.commons.crypto.random.CryptoRandomFactory;
import java.util.Properties;
public class EnvCheck {
public static void main(String[] args) throws Exception {
System.out.println("component=" + Crypto.getComponentName() + "-" + Crypto.getComponentVersion());
System.out.println("nativeLoaded=" + Crypto.isNativeCodeLoaded());
for (String tr : new String[]{"AES/GCM/NoPadding", "AES/CTR/NoPadding", "AES/CBC/PKCS5Padding"}) {
CryptoCipher c = CryptoCipherFactory.getCryptoCipher(tr, new Properties());
System.out.println(tr + " -> " + c.getClass().getName());
c.close();
}
CryptoRandom r = CryptoRandomFactory.getCryptoRandom();
System.out.println("random -> " + r.getClass().getName());
r.close();
}
}
编译并把依赖 jar 复制到 lib 目录后直接运行:
cd /opt/install-demo && mvn -q compile && mvn -q dependency:copy-dependencies -DoutputDirectory=lib && ls lib && java -cp "target/classes:lib/*" EnvCheck
回显(实测):
commons-crypto-1.2.0.jar
jakarta.activation-1.2.2.jar
jakarta.xml.bind-api-2.3.3.jar
jaxb-impl-2.3.7.jar
jna-5.13.0.jar
component=Apache Commons Crypto-1.2.0
nativeLoaded=true
AES/GCM/NoPadding -> org.apache.commons.crypto.cipher.OpenSslCipher
AES/CTR/NoPadding -> org.apache.commons.crypto.cipher.OpenSslCipher
AES/CBC/PKCS5Padding -> org.apache.commons.crypto.cipher.OpenSslCipher
random -> org.apache.commons.crypto.random.OpenSslCryptoRandom
结果解读:三种加密变换全部选中 OpenSslCipher,随机数选中 OpenSslCryptoRandom,说明 OpenSSL 1.1.1 环境下 JNI 路径完整生效,未发生任何回退。若看到 JceCipher,请回到 1.3 节确认 libcrypto.so 符号链接已生成。
四、方案B:官方发行包手动安装
方案B适合不能连 Maven 中央仓库、或只想用 javac/java -cp 轻量验证的场景。
4.1 下载发行包并校验 sha512
cd /opt && curl -fsSLO https://downloads.apache.org/commons/crypto/binaries/commons-crypto-1.2.0-bin.tar.gz && curl -fsSLO https://downloads.apache.org/commons/crypto/binaries/commons-crypto-1.2.0-bin.tar.gz.sha512 && ls -l commons-crypto-1.2.0-bin.tar.gz*
回显(实测):
-rw-r--r-- 1 root root 451014 Oct 13 07:40 commons-crypto-1.2.0-bin.tar.gz
-rw-r--r-- 1 root root 129 Oct 13 07:40 commons-crypto-1.2.0-bin.tar.gz.sha512
发行包 451014 字节;.sha512 文件内容是一段裸哈希,校验时需要拼上文件名再交给 sha512sum -c:
cat commons-crypto-1.2.0-bin.tar.gz.sha512
回显(实测):
fb9084a5d9adcd4df606c7deb9396fa5693443b6a91be12f5de17e4281d3e7d89b526dc6ebd7991569894bde2f9fb67036eb78504cb4fa26fae9b7a99d082051
printf "%s %s\n" "$(cat commons-crypto-1.2.0-bin.tar.gz.sha512)" commons-crypto-1.2.0-bin.tar.gz | sha512sum -c -
回显(实测):
commons-crypto-1.2.0-bin.tar.gz: OK
4.2 解包与目录结构
cd /opt && tar xzf commons-crypto-1.2.0-bin.tar.gz && ls -l commons-crypto-1.2.0/
回显(实测):
total 352
-rw-r--r-- 1 root root 6530 Dec 30 2022 CONTRIBUTING.md
-rw-r--r-- 1 root root 11358 Dec 30 2022 LICENSE.txt
-rw-r--r-- 1 root root 176 Dec 30 2022 NOTICE.txt
-rw-r--r-- 1 root root 16333 Dec 30 2022 README.md
-rw-r--r-- 1 root root 17522 Dec 30 2022 RELEASE-NOTES.txt
drwxr-xr-x 4 root root 4096 Oct 13 07:40 apidocs
-rw-r--r-- 1 root root 118088 Dec 30 2022 commons-crypto-1.2.0-sources.jar
-rw-r--r-- 1 root root 176035 Dec 30 2022 commons-crypto-1.2.0.jar
逐项说明:commons-crypto-1.2.0.jar 是运行所需的唯一 jar(176035 字节,native 库内嵌其中);apidocs 是离线 Javadoc;sources.jar 供阅读源码。
4.3 编译并运行验证代码
把 3.3 节的 EnvCheck.java 放到工作目录(例如 /opt/install-manual),同时复制 jar:
mkdir -p /opt/install-manual && cd /opt/install-manual && cp /opt/commons-crypto-1.2.0/commons-crypto-1.2.0.jar . && javac -encoding UTF-8 -cp commons-crypto-1.2.0.jar EnvCheck.java && echo JAVAC_OK
回显(实测):
JAVAC_OK
java -cp .:commons-crypto-1.2.0.jar EnvCheck
回显(实测):
component=Apache Commons Crypto-1.2.0
nativeLoaded=true
AES/GCM/NoPadding -> org.apache.commons.crypto.cipher.OpenSslCipher
AES/CTR/NoPadding -> org.apache.commons.crypto.cipher.OpenSslCipher
AES/CBC/PKCS5Padding -> org.apache.commons.crypto.cipher.OpenSslCipher
random -> org.apache.commons.crypto.random.OpenSslCryptoRandom
与方案A结果一致。注意 javac -cp 与 java -cp 各自都要带 jar 路径;Linux 下类路径分隔符是冒号。
💡 技术拓展:示例中的
AES/GCM/NoPadding、AES/CTR/NoPadding、AES/CBC/PKCS5Padding是三种常见分组加密模式。选型对比:ECB 无 IV、相同明文块得到相同密文块,已不安全,不建议使用;CBC 需随机 IV、串行加解密、密文有填充膨胀;CTR 把分组密码变成流密码、无填充、可并行,但严禁重复使用同一 IV 加密两份数据;GCM 在 CTR 基础上附加认证标签(默认 128 bit),能发现密文被篡改,是当前推荐模式。本文验证代码三种模式各测一条,实际业务建议优先 GCM、兼容场景用 CTR。
五、方案对比与选型建议
两种方案都能得到可用的 Commons Crypto 环境,差异集中在依赖管理与升级方式上:
| 对比项 | 方案A:Maven 依赖 | 方案B:发行包手动安装 |
|---|---|---|
| 获取方式 | pom 声明坐标,构建时自动下载 | curl 下载 tar.gz 并手工校验 |
| 完整性校验 | Maven 自带仓库校验机制 | 需手工执行 sha512 校验 |
| 传递依赖 | 自动解析(jna、jaxb-impl 等 4 个) | 无传递依赖,单 jar 直接可用 |
| 升级成本 | 改版本号重新构建 | 重新下载解包并替换 -cp 路径 |
| 适用场景 | 常规 Maven 工程、持续集成 | 无外网构建环境、快速验证、脚本工具 |
选型建议:工程开发一律选方案A;临时排查、一次性运维小工具或受限网络环境选方案B。两者可并存——本机用方案B的 jar 做命令行验证,工程内用方案A做集成。
六、多版本管理
CentOS 8 用 alternatives 体系管理同名命令的多个版本。查看 java 当前的指向与候选:
alternatives --display java
回显(实测,节选):
java - status is manual.
link currently points to /usr/lib/jvm/java-17-openjdk-17.0.1.0.12-2.el8_5.x86_64/bin/java
/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.312.b07-2.el8_5.x86_64/jre/bin/java - family java-1.8.0-openjdk.x86_64 priority 1800312
切换默认版本(8 与 17 并存的机器上):
alternatives --config java
该命令为交互式菜单,按提示输入对应编号即可;非交互脚本建议直接用 1.1 节的 alternatives --set java java-17-openjdk.x86_64。再次强调:alternatives 只影响 java/javac 命令,Maven 始终跟随 JAVA_HOME,两者要分别确认。
Commons Crypto 本身只出现在工程的 classpath 里,没有全局安装概念;多版本共存时只需保证运行与编译使用同一个 JDK 主版本。
七、卸载
卸载分两层:移除 dnf 软件包,以及清理手工解压的发行包与工程目录。先用 --assumeno 模拟确认 dnf 将删除的内容(事务被自动拒绝,不会真的删除):
dnf remove --assumeno java-17-openjdk-devel maven 2>&1 | tail -6
回显(实测):
Transaction Summary
==================================================================================================================
Remove 131 Packages
Freed space: 464 M
Operation aborted.
确认清单无误后实际执行卸载:
dnf remove -y java-17-openjdk-devel maven
清理方案B产生的文件:
rm -rf /opt/commons-crypto-1.2.0 /opt/commons-crypto-1.2.0-bin.tar.gz /opt/commons-crypto-1.2.0-bin.tar.gz.sha512 /opt/install-manual /opt/install-demo
验证清理结果:
ls /opt | grep -c crypto || echo "commons-crypto files removed"
回显(实测):
commons-crypto files removed
Commons Crypto 运行时从 jar 内提取到临时目录的 native 库(形如 /tmp/commons-crypto-<uuid>-libcommons-crypto.so)在 JVM 退出时会自动删除,无需手工处理。
八、常见问题 FAQ
Q1:mvn compile 报 Fatal error compiling: invalid target release: 17?
Maven 在用 JDK 8 而不是 17。CentOS 8 的 mvn 启动脚本读取 JAVA_HOME 而不是 alternatives 指向,实测未设置时 mvn -version 显示 Java version: 1.8.0_312, vendor: Red Hat。解法:export JAVA_HOME=/usr/lib/jvm/java-17-openjdk(见 1.2 节),并写入 /etc/profile.d/jdk17.sh 持久化。
Q2:运行时报 Cannot load libcrypto.so (libcrypto.so: cannot open shared object file: No such file or directory),JVM 直接崩溃?
系统只有 libcrypto.so.1.1,缺少未带版本号的 libcrypto.so 符号链接。实测堆栈末尾为:
Caused by: java.lang.UnsatisfiedLinkError: Cannot load libcrypto.so (libcrypto.so: cannot open shared object file: No such file or directory)!
at org.apache.commons.crypto.random.OpenSslCryptoRandomNative.initSR(Native Method)
解法:dnf install -y openssl-devel。注意此时不会自动回退 JCE——随机数工厂只捕获 Exception,而实现类静态初始化抛出的 ExceptionInInitializerError 属于 Error,会直接冒泡终止 JVM,所以必须补齐符号链接。
Q3:怎么确认加密真的走了 OpenSSL 而不是 JCE 回退?
运行 3.3 节的 EnvCheck:输出 OpenSslCipher 即 OpenSSL 路径,JceCipher 即回退路径。CentOS 8 + openssl-devel 的标准结果是三者全部 OpenSslCipher。若想看 native 加载细节,加 JVM 参数 -Dcommons.crypto.debug=true,可看到从 jar 解压 libcommons-crypto.so 到临时目录并 System.load 的完整日志。
Q4:javac 报大量 error: unmappable character (0xE6) for encoding US-ASCII?
POSIX locale 下 javac 默认按 US-ASCII 读取源码,含中文注释的源文件会编译失败。解法:编译时加 -encoding UTF-8(本文方案B已演示);或在 Maven 工程里设置 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>(方案A的 pom 已包含)。
Q5:程序包 org.apache.commons.crypto 不存在,但 jar 明明在同目录?
javac 阶段漏了 -cp commons-crypto-1.2.0.jar,或 java 运行阶段漏了 -cp。完整写法参考 4.3 节:javac -encoding UTF-8 -cp commons-crypto-1.2.0.jar EnvCheck.java 编译、java -cp .:commons-crypto-1.2.0.jar EnvCheck 运行,冒号不能写成 Windows 的分号。
九、参考链接
- Apache Commons Crypto 官方主页:https://commons.apache.org/proper/commons-crypto/
- 官方用户指南:https://commons.apache.org/proper/commons-crypto/userguide.html
- 发行包下载目录:https://downloads.apache.org/commons/crypto/binaries/
- Maven 中央仓库 1.2.0 目录:https://repo1.maven.org/maven2/org/apache/commons/commons-crypto/1.2.0/
- 项目源码仓库:https://github.com/apache/commons-crypto