一、本文目标
本文将完整演示如何在 Windows 环境下构建并使用 liboqs-java,主要包括以下内容:
在 Windows 上编译 liboqs
构建可用的 liboqs-java.jar
运行官方示例验证构建结果
在 Spring Boot 项目中引入该 JAR
通过 Java 代码调用 ML-KEM 等后量子密码算法
二、环境与工具
本文使用的环境如下:
Windows 10 / Windows 11
MinGW-w64
CMake
JDK
Maven
Git
建议使用较新的 JDK 版本,例如 JDK 17 或 JDK 21。本文示例以 JDK 21 为例。
三、先理解 liboqs 与 liboqs-java 的关系
在正式构建之前,需要先理解几个组件之间的关系。
Spring Boot / Java 业务代码
|
| 调用 Java API
v
liboqs-java.jar
|
| JNI 调用
v
oqs-jni.dll
|
| 链接
v
liboqs.a / liboqs
|
| 实际执行算法
v
ML-KEM、ML-DSA 等 PQC 算法
可以简单理解为:
组件 作用
liboqs C 语言实现的后量子密码学算法库
liboqs-java 对 liboqs 的 Java 封装
oqs-jni.dll Java 与 native 层之间的 JNI 桥接库
liboqs-java.jar Java / Spring Boot 项目最终要引入的 JAR 包
因此,正确的构建顺序是:
先构建 liboqs
再构建 liboqs-java
最后在 Java / Spring Boot 项目中引用生成的 JAR
注意:
如果跳过 liboqs 的构建,直接构建 liboqs-java,通常会遇到找不到 oqs.h、找不到 liboqs.a 等问题。
四、推荐项目目录结构
由于需要从 GitHub 获取 liboqs-java 和 liboqs 两个项目源码,建议将目录结构整理为如下形式:
D:\workspace\liboqs-java-main
├── pom.xml
├── README.md
├── examples
│ ├── KEMExample.java
│ ├── SigExample.java
│ └── RandExample.java
├── src
├── liboqs
│ ├── CMakeLists.txt
│ ├── src
│ └── build
│ ├── include
│ │ └── oqs
│ │ └── oqs.h
│ └── lib
│ └── liboqs.a
└── target
└── liboqs-java.jar
如下图所示:
image
其中最关键的是以下几个文件:
liboqs\build\include\oqs\oqs.h
liboqs\build\lib\liboqs.a
target\liboqs-java.jar
只要这些文件都成功生成,说明主构建流程基本已经走通。
五、准备构建工具
需要提前安装以下工具:
工具 作用
MinGW-w64 提供 gcc、g++,用于编译 C 代码和 JNI 代码
CMake 生成并驱动 liboqs 构建
JDK 编译 Java 代码,并提供 JNI 头文件
Maven 构建 liboqs-java 并打包 JAR
Git 拉取源码,非必需,也可以手动下载 ZIP
建议将所有工具都安装到纯英文路径下,不要放在包含中文或空格的目录中。例如:
D:\c_tools\mingw64
D:\java\jdk-21
D:\javaTools\apache-maven-3.9.x
D:\workspace
建议:
native 构建工具对路径比较敏感,中文路径、空格路径有时会导致一些较难排查的问题。为了减少环境问题,建议统一使用英文路径。
六、安装 MinGW-w64
可以使用 MinGW-w64 官方推荐的发行版。下载入口如下:
进入官网后,找到 Downloads,再找到 MinGW-W64-builds。
image
点击后会跳转到 GitHub:
image
选择需要的版本下载即可:
image
下载完成后解压,后续需要将 mingw64\bin 添加到环境变量中。
image
安装完成后,可以在终端中执行:
gcc -v
测试是否安装成功:
image
能看到 GCC 的版本信息,就说明 MinGW-w64 已经可以正常使用。
同时确认以下文件存在:
D:\c_tools\mingw64\bin\gcc.exe
D:\c_tools\mingw64\bin\g++.exe
D:\c_tools\mingw64\bin\mingw32-make.exe
后续 CMake 会通过这些工具来编译 liboqs 和 JNI 代码。
七、安装 CMake
可以使用 winget 安装:
winget install Kitware.CMake
也可以从 CMake 官网下载 Windows x64 Installer:
image
下载后直接运行安装程序即可。
安装时建议勾选:
Add CMake to the system PATH for current user
如下图所示:
image
安装完成后,重新打开终端,执行:
cmake --version
如果能够正常输出版本信息,说明 CMake 已经安装成功。
image
八、安装 JDK
JDK 可以选择 Eclipse Temurin 或 Oracle JDK。
下载地址:
https://www.oracle.com/java/technologies/downloads/
JDK 的安装教程较多,本文不再展开。本文示例使用 JDK 21,假设安装路径为:
D:\java\jdk-21
需要确认以下文件存在:
D:\java\jdk-21\bin\java.exe
D:\java\jdk-21\bin\javac.exe
D:\java\jdk-21\include\jni.h
其中 jni.h 非常重要。
注意:
构建 liboqs-java 时会编译 JNI 代码。如果安装的是 JRE 而不是 JDK,就会缺少 jni.h,从而导致构建失败。
九、安装 Maven
从 Maven 官网下载 binary zip 包:
https://maven.apache.org/download.cgi
image
下载后解压到任意英文路径,例如:
D:\javaTools\apache-maven-3.9.x
image
确认以下文件存在:
D:\javaTools\apache-maven-3.9.x\bin\mvn.cmd
十、配置环境变量
Windows 下构建 native 项目时,环境变量是最容易出问题的一步。
建议配置以下用户变量:
变量名 示例值
JAVA_HOME D:\java\jdk-21
MAVEN_HOME D:\javaTools\apache-maven-3.9.x
MinGW_HOME D:\c_tools\mingw64
然后将以下目录加入 Path:
D:\c_tools\mingw64\bin
D:\java\jdk-21\bin
D:\javaTools\apache-maven-3.9.x\bin
image
重要:
配置完成后,一定要关闭当前已经打开的 PowerShell、cmd 或 IDE 终端,然后重新打开一个新的终端。
已经打开的终端不会自动刷新新的环境变量。
十一、检查构建环境
重新打开 PowerShell,依次执行:
gcc --version
g++ --version
cmake --version
java -version
javac -version
mvn -version
每一条命令都应该正常输出版本信息。
如果某一条命令提示:
不是内部或外部命令
或者:
is not recognized as an internal or external command
说明对应工具没有正确加入 Path。此时不要继续构建,应先检查环境变量配置。
十二、获取源码
进入自己的工作目录:
cd D:\workspace
克隆 liboqs-java:
git clone https://github.com/open-quantum-safe/liboqs-java.git liboqs-java-main
进入项目目录:
cd liboqs-java-main
再将 liboqs 克隆到当前项目内部,目录名建议保持为 liboqs:
git clone https://github.com/open-quantum-safe/liboqs.git liboqs
完成后检查目录是否正确:
Test-Path .\pom.xml
Test-Path .\liboqs\CMakeLists.txt
如果两条命令都返回:
True
说明源码位置没有放错。
如果不使用 Git:
也可以直接从 GitHub 下载 ZIP。
需要注意的是,建议将解压后的目录重命名:
liboqs-java 项目目录命名为 liboqs-java-main
liboqs-main 目录重命名为 liboqs
将 liboqs 放到 liboqs-java-main 目录下
目录示意如下:
image
十三、构建 liboqs
首先进入 liboqs 目录:
cd D:\workspace\liboqs-java-main\liboqs
如果之前构建失败过,建议先删除旧的 build 目录:
Remove-Item -Recurse -Force build -ErrorAction SilentlyContinue
然后执行 CMake 配置命令:
cmake -G "MinGW Makefiles" -DCMAKE_C_COMPILER=gcc
-DCMAKE_ASM_COMPILER=gcc -DBUILD_SHARED_LIBS=OFF
-S . `
-B build
53a66dd270fc1c3679b9c81d2fffe0a9
这里几个参数比较关键:
参数 说明
-G "MinGW Makefiles" 使用 MinGW 构建方式
-DCMAKE_C_COMPILER=gcc 指定 C 编译器
-DCMAKE_ASM_COMPILER=gcc 指定汇编编译器,避免 ASM 编译器找不到
-DBUILD_SHARED_LIBS=OFF 构建静态库 liboqs.a
-S . 指定源码目录为当前目录
-B build 指定构建目录为 build
如果配置成功,最后会看到类似输出:
-- Configuring done
-- Generating done
-- Build files have been written to: .../liboqs/build
5009656d6ff22d5bc280e1fcceedb684
接着开始编译:
cmake --build build -j4
image
其中 -j4 表示使用 4 个线程并行构建。
可以根据机器配置调整:
参数 适用情况
-j2 内存较小或机器配置一般
-j4 常规推荐
-j8 CPU 核心较多、内存充足
liboqs 的构建时间可能会比较长,请耐心等待。
构建完成后如下图所示:
image
构建完成后检查产物:
Test-Path .\build\lib\liboqs.a
Test-Path .\build\include\oqs\oqs.h
image
如果两条命令都返回:
True
说明 liboqs 已经构建完成。
十四、构建 liboqs-java.jar
回到 liboqs-java 项目根目录:
cd D:\workspace\liboqs-java-main
执行 Maven 打包命令:
mvn package -Pwindows "-Dmaven.test.skip=true"
image
这里需要特别注意 PowerShell 下的写法。
-Dmaven.test.skip=true 建议加上双引号,否则 PowerShell 有时会把它解析错,导致 Maven 报类似错误:
Unknown lifecycle phase ".test.skip=true"
如果一切正常,最后会看到:
INFO BUILD SUCCESS
image
检查 JAR 是否生成:
dir .\target\liboqs-java.jar
也可以直接在 target 目录中看到构建好的 liboqs-java.jar。
image
进一步确认 JAR 中是否包含 JNI 动态库:
jar tf .\target\liboqs-java.jar | findstr oqs-jni
正常情况下会看到:
oqs-jni.dll
image
到这里,target\liboqs-java.jar 就是后续 Spring Boot 项目需要引入的 JAR 包。
十五、运行官方 KEM 示例
先编译示例代码:
javac -cp target\liboqs-java.jar examples\KEMExample.java
如果没有输出错误,说明编译成功。
然后运行示例:
java -cp "target\liboqs-java.jar;examples" KEMExample
注意:
Windows 下 classpath 的分隔符是分号 ;,这一点和 Linux / macOS 不同。
Linux / macOS 中通常使用冒号 :。
如果运行成功,输出中会看到类似内容:
Supported KEMs:
...
Enabled KEMs:
...
KEM Details:
Name: ML-KEM-512
...
Shared secrets coincide? true
image
重点关注最后这一行:
Shared secrets coincide? true
这说明双方通过 KEM 算法协商出的共享密钥一致,liboqs-java 已经能够正常调用 native 层算法。
也可以继续测试签名示例:
javac -cp target\liboqs-java.jar examples\SigExample.java
java -cp "target\liboqs-java.jar;examples" SigExample
十六、在 Spring Boot 项目中引入 liboqs-java.jar
构建完成后,就可以把 liboqs-java.jar 放到自己的 Spring Boot 项目中使用。
假设 Spring Boot 项目结构如下:
pqc-demo
├── lib
│ └── liboqs-java.jar
├── pom.xml
└── src
└── main
└── java
将刚才生成的 JAR:
D:\workspace\liboqs-java-main\target\liboqs-java.jar
复制到 Spring Boot 项目的:
pqc-demo\lib\liboqs-java.jar
16.1 方式一:使用 system 依赖
在 Spring Boot 项目的 pom.xml 中加入:
org.openquantumsafe liboqs-java 3.0 system ${project.basedir}/lib/liboqs-java.jar 其中 version 可以根据实际构建的 liboqs-java 版本进行调整。
最稳妥的方式是查看 liboqs-java-main/pom.xml 中的版本号。
这种方式适合本地测试,配置简单直接。
不过需要注意,system 依赖并不是 Maven 推荐的长期方案。如果项目需要团队协作、CI/CD 构建或部署到其他环境,更推荐使用下一种方式。
16.2 方式二:安装到本地 Maven 仓库
进入 liboqs-java.jar 所在目录,执行:
mvn install:install-file "-Dfile=liboqs-java.jar"
"-DgroupId=org.openquantumsafe" "-DartifactId=liboqs-java"
"-Dversion=3.0" `
"-Dpackaging=jar"
安装完成后,Spring Boot 项目中就可以按普通 Maven 依赖方式引入:
org.openquantumsafe liboqs-java 3.0 如果是团队项目,也可以将该 JAR 发布到 Nexus、Artifactory 或公司内部 Maven 仓库中。
推荐:
本地临时测试可以使用 system 依赖;
正式项目更建议安装到 Maven 仓库或发布到私有 Maven 仓库。
十七、在 Spring Boot 中调用 ML-KEM
下面写一个简单的 Service,用于演示如何在 Spring Boot 中调用 KEM 算法。
示例算法使用:
ML-KEM-512
Service 代码如下:
package com.example.pqcdemo.service;
import org.openquantumsafe.KeyEncapsulation;
import org.springframework.stereotype.Service;
import java.util.Arrays;
@Service
public class PqcKemService {
public boolean testMlKem512() throws Exception {
KeyEncapsulation client = null;
KeyEncapsulation server = null;
try {
client = new KeyEncapsulation("ML-KEM-512");
server = new KeyEncapsulation("ML-KEM-512");
// 客户端生成密钥对,并获取公钥
byte[] publicKey = client.generate_keypair();
// 服务端使用客户端公钥封装共享密钥
byte[] ciphertext = server.encap_secret(publicKey);
byte[] serverSharedSecret = server.get_shared_secret();
// 客户端使用密文解封装共享密钥
byte[] clientSharedSecret = client.decap_secret(ciphertext);
// 判断两端共享密钥是否一致
return Arrays.equals(clientSharedSecret, serverSharedSecret);
} finally {
if (client != null) {
client.dispose_KEM();
}
if (server != null) {
server.dispose_KEM();
}
}
}
}
再写一个 Controller 方便测试:
package com.example.pqcdemo.controller;
import com.example.pqcdemo.service.PqcKemService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class PqcController {
private final PqcKemService pqcKemService;
public PqcController(PqcKemService pqcKemService) {
this.pqcKemService = pqcKemService;
}
@GetMapping("/pqc/ml-kem-512/test")
public String testMlKem512() throws Exception {
boolean result = pqcKemService.testMlKem512();
return "ML-KEM-512 shared secret match: " + result;
}
}
启动 Spring Boot 后访问:
http://localhost:8080/pqc/ml-kem-512/test
如果返回:
ML-KEM-512 shared secret match: true
说明 Spring Boot 已经成功调用 liboqs-java 中的 PQC 算法。
十八、查看当前可用的 KEM 算法
如果不确定当前构建出来的库启用了哪些 KEM 算法,可以写一个接口打印出来。
package com.example.pqcdemo.controller;
import org.openquantumsafe.KEMs;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class PqcAlgorithmController {
@GetMapping("/pqc/kems")
public List<String> listEnabledKems() {
return KEMs.get_enabled_KEMs();
}
}
访问:
http://localhost:8080/pqc/kems
即可看到当前 native 库中实际启用的 KEM 算法列表。
需要区分两个概念:
名称 含义
Supported KEMs 库认识哪些算法名称
Enabled KEMs 当前构建产物中真正启用了哪些算法
实际项目中应该以 Enabled KEMs 为准。
十九、Spring Boot 打包时需要注意的问题
如果只是本地运行,一般直接引入 liboqs-java.jar 就可以。
但如果要将项目打成 Spring Boot 可执行 JAR,需要注意依赖是否真的被打进最终包中。
如果使用的是 system 依赖,可以在 spring-boot-maven-plugin 中增加如下配置:
org.springframework.boot spring-boot-maven-plugin true 不过更推荐的方式仍然是:
将 liboqs-java.jar 安装到本地 Maven 仓库
或者发布到公司内部 Maven 私服
然后按普通 Maven 依赖方式引入
这样 Maven、IDE、CI/CD 和部署环境都会更容易处理。
二十、常见问题记录
20.1 gcc 找不到
报错示例:
gcc is not recognized
The C compiler identification is unknown
通常是因为 MinGW 的 bin 目录没有加入 Path。
检查命令:
gcc --version
如果不能正常输出版本信息,需要确认下面路径是否已经加入环境变量:
D:\c_tools\mingw64\bin
修改环境变量后,需要重新打开终端。
20.2 CMake 找不到 ASM 编译器
报错示例:
No CMAKE_ASM_COMPILER could be found
配置 liboqs 时加上:
-DCMAKE_ASM_COMPILER=gcc
完整命令如下:
cmake -G "MinGW Makefiles" -DCMAKE_C_COMPILER=gcc
-DCMAKE_ASM_COMPILER=gcc -DBUILD_SHARED_LIBS=OFF
-S . `
-B build
20.3 找不到 oqs/oqs.h
报错示例:
fatal error: oqs/oqs.h: No such file or directory
这通常说明 liboqs 没有构建成功,或者 liboqs-java 没有找到正确的 include 目录。
先检查:
Test-Path .\liboqs\build\include\oqs\oqs.h
如果返回:
False
需要先回到 liboqs 目录重新构建。
20.4 找不到 liboqs.a
检查文件是否存在:
Test-Path .\liboqs\build\lib\liboqs.a
如果返回:
False
说明 liboqs 构建没有完成。
重新执行:
cd D:\workspace\liboqs-java-main\liboqs
cmake --build build -j4
20.5 找不到 jni.h
报错示例:
fatal error: jni.h: No such file or directory
通常是因为 JAVA_HOME 指向了 JRE,或者没有正确配置 JDK。
检查命令:
Test-Path "$env:JAVA_HOME\include\jni.h"
正常情况下应该返回:
True
如果不是,需要重新设置 JAVA_HOME,确保它指向 JDK 根目录,而不是 JRE 目录。
20.6 PowerShell 中 Maven 参数解析错误
报错示例:
Unknown lifecycle phase ".test.skip=true"
在 PowerShell 中,建议将 Maven 参数用双引号包起来:
mvn package -Pwindows "-Dmaven.test.skip=true"
20.7 Spring Boot 运行时报 native 库加载失败
如果出现 native library 加载失败的问题,先确认 JAR 中是否包含 oqs-jni.dll:
jar tf liboqs-java.jar | findstr oqs-jni
正常情况下应该能看到:
oqs-jni.dll
如果 JAR 中没有该文件,说明 liboqs-java 构建过程不完整,需要重新构建。
如果 JAR 中已经包含 oqs-jni.dll,但 Spring Boot 运行仍然失败,可以先使用普通 Java main 方法运行官方 KEMExample。
这样可以判断问题到底是:
liboqs-java 本身构建失败
还是:
Spring Boot 打包或运行时 classpath 配置问题
二十一、小结
整个流程看起来步骤较多,但真正关键的地方主要有以下几点:
MinGW、CMake、JDK、Maven 必须都能在命令行中正常使用
必须先构建 liboqs
构建 liboqs-java 时需要能够找到 oqs.h 和 liboqs.a
最终生成的 liboqs-java.jar 中需要包含 oqs-jni.dll
Spring Boot 引入时要确保 JAR 被正确加入运行时 classpath
如果官方示例 KEMExample 能够成功运行,并输出:
Shared secrets coincide? true