Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
191 changes: 191 additions & 0 deletions .github/workflows/secure_release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
name: Secure Release & Publish Pipeline

on:
pull_request:
branches: [ master ]
push:
tags:
- 'v*.*.*'

permissions:
contents: write
pages: write
id-token: write

jobs:
verify-integrity:
name: Source Integrity Verification
runs-on: ubuntu-latest

steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Build entlib-native
run: cargo build --release

- name: Generate Source Archives
run: |
VERSION=$(git describe --tags --exact-match 2>/dev/null || echo "dev")
ARCHIVE_NAME="entlib-native-${VERSION}-source"
mkdir -p target/dist
git archive \
--format=tar.gz \
--prefix="${ARCHIVE_NAME}/" \
-o "target/dist/${ARCHIVE_NAME}.tar.gz" \
HEAD
git archive \
--format=zip \
--prefix="${ARCHIVE_NAME}/" \
-o "target/dist/${ARCHIVE_NAME}.zip" \
HEAD
cp ./public/public-key.asc target/dist/public-key.asc
echo "[+] Source archives generated"
ls -lh target/dist/

- name: Import Public Key (Trust Anchor)
run: gpg --import ./public/public-key.asc

- name: Verify PGP Signature
run: |
echo "[*] Verifying PGP signature of RELEASE_HASHES.txt..."
gpg --verify ./public/RELEASE_HASHES.txt.asc ./public/RELEASE_HASHES.txt
echo "[+] PGP signature verification passed"

create-release:
name: Create GitHub Release
if: startsWith(github.ref, 'refs/tags/v')
needs: verify-integrity
runs-on: ubuntu-latest

steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Build entlib-native
run: cargo build --release

- name: Prepare Release Artifacts
env:
GITHUB_REF_NAME: ${{ github.ref_name }}
run: |
VERSION=$(git describe --tags --exact-match)
ARCHIVE_NAME="entlib-native-${VERSION}-source"
mkdir -p target/dist
git archive \
--format=tar.gz \
--prefix="${ARCHIVE_NAME}/" \
-o "target/dist/${ARCHIVE_NAME}.tar.gz" \
HEAD
git archive \
--format=zip \
--prefix="${ARCHIVE_NAME}/" \
-o "target/dist/${ARCHIVE_NAME}.zip" \
HEAD
cp ./public/public-key.asc target/dist/public-key.asc
cp ./public/RELEASE_HASHES.txt target/dist/RELEASE_HASHES.txt
cp ./public/RELEASE_HASHES.txt.asc target/dist/RELEASE_HASHES.txt.asc

- name: Extract Tag Version
id: version
run: echo "tag=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT"

- name: Create GitHub Release
uses: softprops/action-gh-release@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
name: "entlib-native ${{ steps.version.outputs.tag }}"
body: |
## Source Distribution

| File | Description |
|------|-------------|
| `entlib-native-${{ steps.version.outputs.tag }}-source.tar.gz` | Source archive (tar.gz) |
| `entlib-native-${{ steps.version.outputs.tag }}-source.zip` | Source archive (zip) |
| `RELEASE_HASHES.txt` | SHA3-512 + BLAKE3 checksums |
| `RELEASE_HASHES.txt.asc` | PGP detached signature |
| `public-key.asc` | PGP public key (Trust Anchor) |

## Verify Integrity

```bash
gpg --import public-key.asc
gpg --verify RELEASE_HASHES.txt.asc RELEASE_HASHES.txt
```
files: |
./target/dist/entlib-native-*-source.tar.gz
./target/dist/entlib-native-*-source.zip
./target/dist/RELEASE_HASHES.txt
./target/dist/RELEASE_HASHES.txt.asc
./target/dist/public-key.asc

publish-trust-anchor:
name: Publish Trust Anchor to GitHub Pages
if: startsWith(github.ref, 'refs/tags/v')
needs: create-release
runs-on: ubuntu-latest

environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}

steps:
- name: Checkout Repository
uses: actions/checkout@v4

- name: Extract Tag Version
id: version
run: echo "tag=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT"

- name: Build Pages Site
env:
RELEASE_TAG: ${{ steps.version.outputs.tag }}
run: |
mkdir -p _site/keys "_site/releases/${RELEASE_TAG}"

cp ./public/public-key.asc _site/keys/public-key.asc

cp ./public/RELEASE_HASHES.txt \
"_site/releases/${RELEASE_TAG}/RELEASE_HASHES.txt"
cp ./public/RELEASE_HASHES.txt.asc \
"_site/releases/${RELEASE_TAG}/RELEASE_HASHES.txt.asc"

cat > _site/index.html << 'PAGE'
<!DOCTYPE html>
<html lang="en">
<head><meta charset="utf-8"><title>entlib-native Trust Anchor</title></head>
<body>
<h1>entlib-native Trust Anchor</h1>
<h2>PGP Public Key</h2>
<p><a href="keys/public-key.asc">public-key.asc</a></p>
<h2>Verification</h2>
<pre>
# 1. Import the public key
curl -sO https://quant-off.github.io/entlib-native/keys/public-key.asc
gpg --import public-key.asc

# 2. Download the release hashes and signature
VERSION="vX.Y.Z"
curl -sO "https://quant-off.github.io/entlib-native/releases/${VERSION}/RELEASE_HASHES.txt"
curl -sO "https://quant-off.github.io/entlib-native/releases/${VERSION}/RELEASE_HASHES.txt.asc"

# 3. Verify the signature
gpg --verify RELEASE_HASHES.txt.asc RELEASE_HASHES.txt
</pre>
</body>
</html>
PAGE

- name: Upload Pages Artifact
uses: actions/upload-pages-artifact@v3
with:
path: _site

- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
69 changes: 69 additions & 0 deletions cli/src/cmd/blake.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use super::hex_encode;
use crate::input;
use clap::Subcommand;
use entlib_native_blake::file::{blake2b as blake2b_file, blake3 as blake3_file};
use entlib_native_blake::{Blake2b, Blake3};

#[derive(Subcommand)]
Expand All @@ -19,6 +20,32 @@ pub(crate) enum Ops {
#[arg(long)]
raw: bool,
},
/// BLAKE2b 파일 스트리밍 해시
#[command(name = "2b-file")]
Blake2bFile {
/// 출력 바이트 수 (1-64, 기본: 32)
#[arg(long, default_value_t = 32)]
output_len: usize,
/// 해시할 파일 경로
file: String,
#[arg(long)]
out_file: Option<String>,
#[arg(long)]
raw: bool,
},
/// BLAKE3 파일 스트리밍 해시
#[command(name = "3-file")]
Blake3File {
/// 출력 바이트 수 (기본: 32)
#[arg(long, default_value_t = 32)]
output_len: usize,
/// 해시할 파일 경로
file: String,
#[arg(long)]
out_file: Option<String>,
#[arg(long)]
raw: bool,
},
/// BLAKE3 (32-byte 기본 출력, XOF 지원)
#[command(name = "3")]
Blake3 {
Expand All @@ -37,6 +64,48 @@ pub(crate) enum Ops {

pub(crate) fn run(op: Ops) {
match op {
Ops::Blake2bFile {
output_len,
file,
out_file,
raw,
} => {
if !(1..=64).contains(&output_len) {
eprintln!("output_len은 1-64 범위여야 합니다");
std::process::exit(1);
}
match blake2b_file::hash_file(&file, output_len) {
Ok(d) => {
let result = if raw { d } else { hex_encode(d) };
input::write_output(result, out_file.as_deref(), false);
}
Err(e) => {
eprintln!("파일 해시 오류: {e}");
std::process::exit(1);
}
}
}
Ops::Blake3File {
output_len,
file,
out_file,
raw,
} => {
if output_len == 0 {
eprintln!("output_len은 1 이상이어야 합니다");
std::process::exit(1);
}
match blake3_file::hash_file(&file, output_len) {
Ok(d) => {
let result = if raw { d } else { hex_encode(d) };
input::write_output(result, out_file.as_deref(), false);
}
Err(e) => {
eprintln!("파일 해시 오류: {e}");
std::process::exit(1);
}
}
}
Ops::Blake2b {
output_len,
in_file,
Expand Down
40 changes: 40 additions & 0 deletions cli/src/cmd/sha3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use super::hex_encode;
use crate::input;
use clap::Subcommand;
use entlib_native_sha3::api::{SHA3_224, SHA3_256, SHA3_384, SHA3_512, SHAKE128, SHAKE256};
use entlib_native_sha3::file::{sha3_224 as sha3_224_file, sha3_256 as sha3_256_file, sha3_384 as sha3_384_file, sha3_512 as sha3_512_file};

#[derive(Subcommand)]
pub(crate) enum Ops {
Expand Down Expand Up @@ -42,6 +43,18 @@ pub(crate) enum Ops {
#[arg(long)]
raw: bool,
},
/// 파일 스트리밍 해시 (SHA3-224/256/384/512)
HashFile {
/// SHA3 변형 (224, 256, 384, 512)
#[arg(long, default_value_t = 256)]
bits: u16,
/// 해시할 파일 경로
file: String,
#[arg(long)]
out_file: Option<String>,
#[arg(long)]
raw: bool,
},
/// XOF SHAKE128 (128-bit security, 가변 출력 길이)
Shake128 {
/// 출력 바이트 수
Expand Down Expand Up @@ -126,6 +139,33 @@ macro_rules! run_xof {

pub(crate) fn run(op: Ops) {
match op {
Ops::HashFile {
bits,
file,
out_file,
raw,
} => {
let digest = match bits {
224 => sha3_224_file::hash_file(&file),
256 => sha3_256_file::hash_file(&file),
384 => sha3_384_file::hash_file(&file),
512 => sha3_512_file::hash_file(&file),
_ => {
eprintln!("지원하지 않는 비트 길이: {bits} (224, 256, 384, 512 중 선택)");
std::process::exit(1);
}
};
match digest {
Ok(d) => {
let result = if raw { d } else { hex_encode(d) };
input::write_output(result, out_file.as_deref(), false);
}
Err(e) => {
eprintln!("파일 해시 오류: {e}");
std::process::exit(1);
}
}
}
Ops::Sha3_224 {
in_file,
out_file,
Expand Down
4 changes: 4 additions & 0 deletions public/RELEASE_HASHES.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
SHA3-512 ./entlib-native-dev-source.tar.gz : 6b7f36dc2dae00c9fde2368f8c8d94505c29dfabc8426a825866e9fd26f0bccb360677ed2a9ccc4b25aa50b07e933d6a7d88dcf73df7de24ff4065cadf4e0846
BLAKE3 ./entlib-native-dev-source.tar.gz : d19e1f445997446bf99b0697bd846b872a252bdbbad819b5d8b4c23106ca9281
SHA3-512 ./entlib-native-dev-source.zip : 012a9dc5d51ca2928a8ddd6d542f3cbf8a71e06827742e917a638b2a82d11bb43e4d8ee4c8c510a5713542d9b23f0fcbb9c33a79f520c2d271e7304281314945
BLAKE3 ./entlib-native-dev-source.zip : df88ed5354a2502b60311f430af41751aeb795ba8d6d3e76f6ce0c56486858c6
7 changes: 7 additions & 0 deletions public/RELEASE_HASHES.txt.asc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
-----BEGIN PGP SIGNATURE-----

iHUEABYKAB0WIQTkuuTQ1yxQ1k2xdRZbK81mYBTjYQUCaceCFAAKCRBbK81mYBTj
YYFAAQDnu0Yko0v2SqhAr4aL33nRiykvMZ2w/+4N13HCqfNWBgD+I/4lzPs7hW5I
RiQD9cfoDB0kzfFQGuxJMBu2O9n/KwQ=
=niwE
-----END PGP SIGNATURE-----
Loading