Windows x64 构建 liboqs-java教程

Windows 下构建 liboqs-java,实现PQC算法的调用

liboqs-java 并不是一个纯 Java 库,它底层依赖的是由 C 语言实现的后量子密码学库 liboqs

也就是说,虽然我们最终是在 Java / Spring Boot 项目中调用 PQC 算法,但真正执行算法逻辑的是 native 层。Java 代码通过 JNI 调用 oqs-jni.dll,再由该动态库链接并调用底层的 liboqs

本文链接: https://www.cnblogs.com/20222423lpy/p/20652105
转载时请注明出处。


一、本文目标

本文将完整演示如何在 Windows 环境下构建并使用 liboqs-java,主要包括以下内容:

  1. 在 Windows 上编译 liboqs
  2. 构建可用的 liboqs-java.jar
  3. 运行官方示例验证构建结果
  4. 在 Spring Boot 项目中引入该 JAR
  5. 通过 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-javaliboqs 两个项目源码,建议将目录结构整理为如下形式:

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 提供 gccg++,用于编译 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 官方推荐的发行版。下载入口如下:

https://www.mingw-w64.org/

进入官网后,找到 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:

https://cmake.org/download/

image

下载后直接运行安装程序即可。

安装时建议勾选:

Add CMake to the system PATH for current user

如下图所示:

image

安装完成后,重新打开终端,执行:

cmake --version

如果能够正常输出版本信息,说明 CMake 已经安装成功。

image


八、安装 JDK

JDK 可以选择 Eclipse Temurin 或 Oracle JDK。

下载地址:

https://adoptium.net/
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 中加入:

<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 构建或部署到其他环境,更推荐使用下一种方式。


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 依赖方式引入:

<dependency>
    <groupId>org.openquantumsafe</groupId>
    <artifactId>liboqs-java</artifactId>
    <version>3.0</version>
</dependency>

如果是团队项目,也可以将该 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 中增加如下配置:

<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 依赖方式引入

这样 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 配置问题

二十一、小结

整个流程看起来步骤较多,但真正关键的地方主要有以下几点:

  1. MinGW、CMake、JDK、Maven 必须都能在命令行中正常使用
  2. 必须先构建 liboqs
  3. 构建 liboqs-java 时需要能够找到 oqs.hliboqs.a
  4. 最终生成的 liboqs-java.jar 中需要包含 oqs-jni.dll
  5. Spring Boot 引入时要确保 JAR 被正确加入运行时 classpath

如果官方示例 KEMExample 能够成功运行,并输出:

Shared secrets coincide? true

就说明 liboqs-java 已经能够正常调用 native 层的 PQC 算法。

后续在 Spring Boot 中调用 ML-KEM、ML-DSA 等后量子密码算法,本质上就只是普通 Java API 调用的问题了。


二十二、参考资料

posted on 2026-06-19 14:37  云烟飘渺PM  阅读(173)  评论(0)    收藏  举报