Windows x64 构建 liboqs-java教程

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

liboqs-java 本身不是一个纯 Java 库,它底层依赖 liboqs 这个 C 语言实现的后量子密码学库。也就是说,我们最终虽然是在 Java / Spring Boot 项目里调用 PQC 算法,但真正执行算法逻辑的是 native 层。

本教程的目标如下:

  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

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 包

所以构建顺序一定是:

  1. 先构建 liboqs
  2. 再构建 liboqs-java
  3. 最后在 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 提供 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 构建工具对路径比较敏感,中文路径或空格路径有时会带来一些很难排查的问题。


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. 小结

整个流程看起来步骤不少,但真正关键的地方其实只有几个:

  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

那么后续在 Spring Boot 中调用 ML-KEM、ML-DSA 等 PQC 算法,基本就是普通 Java API 调用的问题了。

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