Windows x64 构建 liboqs-java教程
Windows 下构建 liboqs-java,实现 PQC 算法的调用
liboqs-java 本身不是一个纯 Java 库,它底层依赖 liboqs 这个 C 语言实现的后量子密码学库。也就是说,我们最终虽然是在 Java / Spring Boot 项目里调用 PQC 算法,但真正执行算法逻辑的是 native 层。
本教程的目标如下:
- 在 Windows 上编译
liboqs - 构建出可用的
liboqs-java.jar - 运行官方示例验证构建是否成功
- 在 Spring Boot 项目中引入该 JAR
- 通过 Java 代码调用 ML-KEM 等后量子密码算法
环境与工具
Windows 10 / Windows 11
+ MinGW-w64
+ CMake
+ JDK
+ Maven
1. 先理解 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 项目最终要引入的 JAR 包 |
所以构建顺序一定是:
- 先构建
liboqs - 再构建
liboqs-java - 最后在 Java / Spring Boot 项目中引用生成的 JAR
如果跳过第一步,直接构建 liboqs-java,通常会遇到找不到 oqs.h、找不到 liboqs.a 之类的问题。
2. 构建时候的项目目录结构
因为需要在github上获取liboqs与libqos-java两个项目源码,构建时候建议最终的目录结构如下:
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
其中比较关键的是这几个文件:
liboqs\build\include\oqs\oqs.h
liboqs\build\lib\liboqs.a
target\liboqs-java.jar
只要这几个文件都生成了,说明主流程基本走通了。
3. 准备构建工具
需要提前安装下面几个工具。
| 工具 | 用途 |
|---|---|
| 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 构建工具对路径比较敏感,中文路径或空格路径有时会带来一些很难排查的问题。
4. 安装 MinGW-w64
可以使用 WinLibs 提供的 MinGW-w64 发行版。
下载地址:
https://winlibs.com/
选择 Windows x86_64 版本即可。下载后解压到类似下面的目录:
D:\c_tools\mingw64
确认下面几个文件存在:
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 代码。
5. 安装 CMake
可以使用 winget 安装:
winget install Kitware.CMake
也可以从官网下载 Windows x64 Installer:
https://cmake.org/download/
安装时建议勾选:
Add CMake to the system PATH
安装完成后,重新打开一个 PowerShell,执行:
cmake --version
能看到版本号就说明 CMake 已经可以正常使用。
6. 安装 JDK
JDK 可以使用 Eclipse Temurin 或 Oracle JDK。
下载地址:
https://adoptium.net/
https://www.oracle.com/java/technologies/downloads/
本文示例使用 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,就会缺少这个头文件。
7. 安装 Maven
从 Maven 官网下载 binary zip 包:
https://maven.apache.org/download.cgi
解压到:
D:\javaTools\apache-maven-3.9.x
确认下面文件存在:
D:\javaTools\apache-maven-3.9.x\bin\mvn.cmd
8. 配置环境变量
这是 Windows 下最容易出问题的一步。
建议配置以下用户变量:
| 变量名 | 示例值 |
|---|---|
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
配置完成后,一定要关闭当前已经打开的 PowerShell、cmd 或 IDE 终端,然后重新打开一个新的终端。
环境变量不会自动刷新到已经打开的终端窗口里。
9. 检查构建环境
重新打开 PowerShell,依次执行下面几条命令:
gcc --version
g++ --version
cmake --version
java -version
javac -version
mvn -version
每一条都应该正常输出版本信息。
如果某一条提示“不是内部或外部命令”,先不要继续构建,回去检查 Path 是否配置正确。
10. 获取源码
进入自己的工作目录:
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对应的目录 liboqs-main目录重命名为 liboqs,并放到 liboqs-java-main 目录下。
11. 构建 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
这里几个参数比较关键:
| 参数 | 说明 |
|---|---|
-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
接着开始编译:
cmake --build build -j4
-j4 表示使用 4 个线程并行构建。如果机器配置较好,可以改成 -j8;如果内存比较紧张,可以改成 -j2。
构建完成后检查产物:
Test-Path .\build\lib\liboqs.a
Test-Path .\build\include\oqs\oqs.h
两条命令都返回 True,说明 liboqs 已经构建完成。
12. 构建 liboqs-java.jar
回到 liboqs-java 项目根目录:
cd D:\workspace\liboqs-java-main
执行 Maven 打包:
mvn package -Pwindows "-Dmaven.test.skip=true"
这里要注意 PowerShell 下的写法。
-Dmaven.test.skip=true 建议加上双引号,否则 PowerShell 有时会把它解析错,导致 Maven 报类似下面的错误:
Unknown lifecycle phase ".test.skip=true"
如果一切正常,最后会看到:
[INFO] BUILD SUCCESS
检查 JAR 是否生成:
dir .\target\liboqs-java.jar
也可以确认 JAR 中是否包含 JNI 动态库:
jar tf .\target\liboqs-java.jar | findstr oqs-jni
正常情况下会看到:
oqs-jni.dll
这一步成功后,target\liboqs-java.jar 就是后面 Spring Boot 项目需要引入的包。
13. 运行官方 KEM 示例
先编译示例代码:
javac -cp target\liboqs-java.jar examples\KEMExample.java
如果没有输出错误,说明编译成功。
然后运行:
java -cp "target\liboqs-java.jar;examples\" KEMExample
Windows 下 classpath 的分隔符是分号 ;,这一点和 Linux / macOS 不一样。
如果运行成功,输出中会看到类似内容:
Supported KEMs:
...
Enabled KEMs:
...
KEM Details:
Name: ML-KEM-512
...
Shared secrets coincide? true
重点看最后这一行:
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
14. 在 Spring Boot 项目中引入 liboqs-java.jar
构建完成后,就可以把 liboqs-java.jar 放到自己的 Spring Boot 项目里使用。
假设 Spring Boot 项目结构如下:
pqc-demo
├── lib
│ └── liboqs-java.jar
├── pom.xml
└── src
└── main
└── java
把刚才生成的文件复制过去:
D:\workspace\liboqs-java-main\target\liboqs-java.jar
放到:
pqc-demo\lib\liboqs-java.jar
14.1 方式一:直接使用 system 依赖
在 pom.xml 中加入:
<dependency>
<groupId>org.openquantumsafe</groupId>
<artifactId>liboqs-java</artifactId>
<version>3.0</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/liboqs-java.jar</systemPath>
</dependency>
这里的 version 可以根据你实际构建的 liboqs-java 版本调整。最稳妥的方式是看一下 liboqs-java-main/pom.xml 中的版本号。
这种方式适合本地测试,简单直接。
不过 system 依赖不是 Maven 推荐的长期方案。如果项目需要给团队其他人使用,或者要放到 CI/CD 里构建,更建议使用下面这种方式。
14.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 依赖:
<dependency>
<groupId>org.openquantumsafe</groupId>
<artifactId>liboqs-java</artifactId>
<version>3.0</version>
</dependency>
如果是团队项目,也可以把这个 JAR 发布到 Nexus、Artifactory 或公司内部 Maven 仓库中。
15. Spring Boot 中调用 ML-KEM
下面写一个简单的 Service,用来演示如何在 Spring Boot 中调用 KEM 算法。
示例使用 ML-KEM-512。
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 算法。
16. 查看当前可用的 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 为准。
17. Spring Boot 打包时需要注意的问题
如果你只是本地运行,一般直接引入 liboqs-java.jar 就可以。
但如果要打成 Spring Boot 可执行 JAR,需要注意依赖是否真的被打进最终包里。
如果使用 system 依赖,可以在 spring-boot-maven-plugin 中增加配置:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<includeSystemScope>true</includeSystemScope>
</configuration>
</plugin>
</plugins>
</build>
不过更推荐的方式还是把 liboqs-java.jar 安装到本地 Maven 仓库,或者发布到私有 Maven 仓库,然后按普通依赖方式引入。
这样 Maven、IDE、CI/CD 都更容易处理。
18. 常见问题记录
18.1 gcc 找不到
报错示例:
gcc is not recognized
The C compiler identification is unknown
一般是 MinGW 的 bin 目录没有加入 Path。
检查:
gcc --version
如果不正常,确认下面路径是否已经加入环境变量:
D:\c_tools\mingw64\bin
修改后需要重新打开终端。
18.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
18.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 目录重新构建。
18.4 找不到 liboqs.a
检查文件是否存在:
Test-Path .\liboqs\build\lib\liboqs.a
如果不存在,说明 liboqs 构建没有完成,重新执行:
cd D:\workspace\liboqs-java-main\liboqs
cmake --build build -j4
18.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 根目录。
18.6 PowerShell 中 Maven 参数解析错误
报错示例:
Unknown lifecycle phase ".test.skip=true"
把 Maven 参数用双引号包起来:
mvn package -Pwindows "-Dmaven.test.skip=true"
18.7 Spring Boot 运行时报 native 库相关错误
如果出现类似 native library 加载失败的问题,先确认:
jar tf liboqs-java.jar | findstr oqs-jni
能看到:
oqs-jni.dll
如果 JAR 中没有这个文件,说明 liboqs-java 构建过程不完整,需要重新构建。
如果 JAR 中有 oqs-jni.dll,但 Spring Boot 运行仍然失败,可以先在普通 Java main 方法中运行官方 KEMExample,确认是不是 Spring Boot 打包方式导致的问题。
19. 一组完整构建命令
如果工具和环境变量都已经配置好,可以直接按下面流程执行。
把路径换成自己的实际路径:
$PROJECT = "D:\workspace\liboqs-java-main"
cd "$PROJECT\liboqs"
Remove-Item -Recurse -Force build -ErrorAction SilentlyContinue
cmake -G "MinGW Makefiles" `
-DCMAKE_C_COMPILER=gcc `
-DCMAKE_ASM_COMPILER=gcc `
-DBUILD_SHARED_LIBS=OFF `
-S . `
-B build
cmake --build build -j4
cd $PROJECT
mvn package -Pwindows "-Dmaven.test.skip=true"
javac -cp target\liboqs-java.jar examples\KEMExample.java
java -cp "target\liboqs-java.jar;examples\" KEMExample
看到:
Shared secrets coincide? true
就说明构建成功。
21. 小结
整个流程看起来步骤不少,但真正关键的地方其实只有几个:
- 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
那么后续在 Spring Boot 中调用 ML-KEM、ML-DSA 等 PQC 算法,基本就是普通 Java API 调用的问题了。
浙公网安备 33010602011771号