mirror of
https://github.com/laosb/swift-minisign.git
synced 2025-04-30 18:01:08 +00:00
Initial fork.
This commit is contained in:
parent
bea7edf8c4
commit
e162e99e2c
8 changed files with 450 additions and 23 deletions
4
.spi.yml
Normal file
4
.spi.yml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
version: 1
|
||||||
|
builder:
|
||||||
|
configs:
|
||||||
|
- documentation_targets: [Minisign]
|
79
.swiftpm/xcode/xcshareddata/xcschemes/Minisign.xcscheme
Normal file
79
.swiftpm/xcode/xcshareddata/xcschemes/Minisign.xcscheme
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme
|
||||||
|
LastUpgradeVersion = "1630"
|
||||||
|
version = "1.7">
|
||||||
|
<BuildAction
|
||||||
|
parallelizeBuildables = "YES"
|
||||||
|
buildImplicitDependencies = "YES"
|
||||||
|
buildArchitectures = "Automatic">
|
||||||
|
<BuildActionEntries>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "Minisign"
|
||||||
|
BuildableName = "Minisign"
|
||||||
|
BlueprintName = "Minisign"
|
||||||
|
ReferencedContainer = "container:">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
</BuildActionEntries>
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
shouldAutocreateTestPlan = "YES">
|
||||||
|
<Testables>
|
||||||
|
<TestableReference
|
||||||
|
skipped = "NO">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "MinisignTests"
|
||||||
|
BuildableName = "MinisignTests"
|
||||||
|
BlueprintName = "MinisignTests"
|
||||||
|
ReferencedContainer = "container:">
|
||||||
|
</BuildableReference>
|
||||||
|
</TestableReference>
|
||||||
|
</Testables>
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
launchStyle = "0"
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
debugServiceExtension = "internal"
|
||||||
|
allowLocationSimulation = "YES">
|
||||||
|
</LaunchAction>
|
||||||
|
<ProfileAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
savedToolIdentifier = ""
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
debugDocumentVersioning = "YES">
|
||||||
|
<MacroExpansion>
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "Minisign"
|
||||||
|
BuildableName = "Minisign"
|
||||||
|
BlueprintName = "Minisign"
|
||||||
|
ReferencedContainer = "container:">
|
||||||
|
</BuildableReference>
|
||||||
|
</MacroExpansion>
|
||||||
|
</ProfileAction>
|
||||||
|
<AnalyzeAction
|
||||||
|
buildConfiguration = "Debug">
|
||||||
|
</AnalyzeAction>
|
||||||
|
<ArchiveAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
revealArchiveInOrganizer = "YES">
|
||||||
|
</ArchiveAction>
|
||||||
|
</Scheme>
|
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2021 Stephen Larew, 2025 Shibo Lyu
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
24
Package.resolved
Normal file
24
Package.resolved
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
"originHash" : "def130774b50dc2ba17b29adfc982eea080e276d775b67d2d3d92bd096b2287d",
|
||||||
|
"pins" : [
|
||||||
|
{
|
||||||
|
"identity" : "swift-blake2",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/lovetodream/swift-blake2",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "b8074b87567037046445ce0859644c283dcce8cc",
|
||||||
|
"version" : "0.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "swift-crypto",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/apple/swift-crypto",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "60f13f60c4d093691934dc6cfdf5f508ada1f894",
|
||||||
|
"version" : "2.6.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version" : 3
|
||||||
|
}
|
|
@ -5,17 +5,42 @@ import PackageDescription
|
||||||
|
|
||||||
let package = Package(
|
let package = Package(
|
||||||
name: "Minisign",
|
name: "Minisign",
|
||||||
|
platforms: [
|
||||||
|
.macOS(.v10_15),
|
||||||
|
.iOS(.v13),
|
||||||
|
.visionOS(.v1),
|
||||||
|
.tvOS(.v13),
|
||||||
|
.watchOS(.v6)
|
||||||
|
],
|
||||||
products: [
|
products: [
|
||||||
// Products define the executables and libraries a package produces, making them visible to other packages.
|
// Products define the executables and libraries a package produces, making them visible to other packages.
|
||||||
.library(
|
.library(
|
||||||
name: "Minisign",
|
name: "Minisign",
|
||||||
targets: ["Minisign"]),
|
targets: ["Minisign"]
|
||||||
|
)
|
||||||
|
],
|
||||||
|
traits: [
|
||||||
|
.init(
|
||||||
|
name: "UseSwiftCrypto",
|
||||||
|
description:
|
||||||
|
"Use Swift Crypto instead of Apple's CryptoKit. If targeting Apple platforms only, remove this trait to cut dependency on Swift Crypto."
|
||||||
|
),
|
||||||
|
.default(enabledTraits: ["UseSwiftCrypto"]),
|
||||||
|
],
|
||||||
|
dependencies: [
|
||||||
|
.package(url: "https://github.com/apple/swift-crypto", from: "2.0.0"),
|
||||||
|
.package(url: "https://github.com/lovetodream/swift-blake2", from: "0.1.0")
|
||||||
],
|
],
|
||||||
targets: [
|
targets: [
|
||||||
// Targets are the basic building blocks of a package, defining a module or a test suite.
|
// Targets are the basic building blocks of a package, defining a module or a test suite.
|
||||||
// Targets can depend on other targets in this package and products from dependencies.
|
// Targets can depend on other targets in this package and products from dependencies.
|
||||||
.target(
|
.target(
|
||||||
name: "Minisign"),
|
name: "Minisign",
|
||||||
|
dependencies: [
|
||||||
|
.product(name: "Crypto", package: "swift-crypto", condition: .when(traits: ["UseSwiftCrypto"])),
|
||||||
|
.product(name: "BLAKE2", package: "swift-blake2")
|
||||||
|
]
|
||||||
|
),
|
||||||
.testTarget(
|
.testTarget(
|
||||||
name: "MinisignTests",
|
name: "MinisignTests",
|
||||||
dependencies: ["Minisign"]
|
dependencies: ["Minisign"]
|
||||||
|
|
15
README.md
Normal file
15
README.md
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
# Swift Minisign
|
||||||
|
|
||||||
|
Swift implementation of Minisign, a simple and secure tool for signing and verifying files.
|
||||||
|
|
||||||
|
This is a fork of [slarew/swift-minisign](https://github.com/slarew/swift-minisign), with these improvements:
|
||||||
|
|
||||||
|
- Convenient & efficient API for verifying (big) files
|
||||||
|
- Replaced C wrapping `swift-crypto-blake2` with [pure Swift implementation of blake2b](https://github.com/lovetodream/swift-blake2).
|
||||||
|
- For Apple platforms, Swift Crypto dependency is now optional, controllable via trait `UseSwiftCrypto`.
|
||||||
|
|
||||||
|
*but still, only signature verification is supported, signing not yet!*
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[MIT](LICENSE).
|
|
@ -1,2 +1,157 @@
|
||||||
// The Swift Programming Language
|
// SPDX-License-Identifier: MIT
|
||||||
// https://docs.swift.org/swift-book
|
// Based on https://github.com/slarew/swift-minisign
|
||||||
|
// Copyright 2021 Stephen Larew, 2025 Shibo Lyu
|
||||||
|
|
||||||
|
import BLAKE2
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
#if UseSwiftCrypto
|
||||||
|
import Crypto
|
||||||
|
#else
|
||||||
|
import CryptoKit
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public enum SignatureAlgorithm: RawRepresentable {
|
||||||
|
case pureEdDSA
|
||||||
|
case hashedEdDSA
|
||||||
|
|
||||||
|
private static let dataEd = "Ed".data(using: .utf8)!
|
||||||
|
private static let dataED = "ED".data(using: .utf8)!
|
||||||
|
|
||||||
|
public init?(rawValue: Data) {
|
||||||
|
if rawValue == Self.dataEd {
|
||||||
|
self = .pureEdDSA
|
||||||
|
} else if rawValue == Self.dataED {
|
||||||
|
self = .hashedEdDSA
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public var rawValue: Data {
|
||||||
|
switch self {
|
||||||
|
case .pureEdDSA: return Self.dataEd
|
||||||
|
case .hashedEdDSA: return Self.dataED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private let untrustedCommentHeader = "untrusted comment: ".data(using: .utf8)!
|
||||||
|
private let trustedCommentHeader = "trusted comment: ".data(using: .utf8)!
|
||||||
|
|
||||||
|
public struct PublicKey {
|
||||||
|
public let untrustedComment: String
|
||||||
|
public let signatureAlgorithm: SignatureAlgorithm
|
||||||
|
public let keyID: Data
|
||||||
|
public let publicKey: Curve25519.Signing.PublicKey
|
||||||
|
|
||||||
|
public init?<D>(text: D) where D: DataProtocol {
|
||||||
|
let lines = text.split(separator: UInt8(ascii: "\n"), maxSplits: 2, omittingEmptySubsequences: false)
|
||||||
|
guard lines.count == 2 || lines[2].isEmpty else { return nil }
|
||||||
|
guard lines[0].starts(with: untrustedCommentHeader) else { return nil }
|
||||||
|
guard
|
||||||
|
let untrustedComment = String(
|
||||||
|
data: Data(lines[0].suffix(from: untrustedCommentHeader.count as! D.Index)),
|
||||||
|
encoding: .utf8
|
||||||
|
)
|
||||||
|
else { return nil }
|
||||||
|
self.untrustedComment = untrustedComment
|
||||||
|
guard let decLine2 = Data(base64Encoded: Data(lines[1]), options: []) else { return nil }
|
||||||
|
guard decLine2.count == 42 else { return nil }
|
||||||
|
guard let sigAlgo = SignatureAlgorithm(rawValue: decLine2.prefix(2)),
|
||||||
|
sigAlgo == .pureEdDSA
|
||||||
|
else { return nil }
|
||||||
|
self.signatureAlgorithm = sigAlgo
|
||||||
|
self.keyID = decLine2[2..<10]
|
||||||
|
guard let publicKey = try? Curve25519.Signing.PublicKey(rawRepresentation: decLine2[10..<42]) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
self.publicKey = publicKey
|
||||||
|
}
|
||||||
|
|
||||||
|
public func isValidSignature<D>(_ signature: Signature, for data: D) -> Bool where D: DataProtocol {
|
||||||
|
guard signature.keyID == keyID else { return false }
|
||||||
|
switch signature.signatureAlgorithm {
|
||||||
|
case .pureEdDSA:
|
||||||
|
guard publicKey.isValidSignature(signature.signature, for: data) else { return false }
|
||||||
|
case .hashedEdDSA:
|
||||||
|
let digest = try! BLAKE2b.hash(data: data) // Default parameters are guaranteed to be correct
|
||||||
|
guard publicKey.isValidSignature(signature.signature, for: digest) else { return false }
|
||||||
|
}
|
||||||
|
let globalData = signature.signature + signature.trustedCommentData
|
||||||
|
guard publicKey.isValidSignature(signature.globalSignature, for: globalData) else { return false }
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verify the signature for a file using the hashed EdDSA algorithm.
|
||||||
|
///
|
||||||
|
/// This method reads the file in chunks to avoid loading the entire file into memory, but does so in a blocking manner.
|
||||||
|
/// It's recommended to use this method in a background thread or task.
|
||||||
|
public func isValidSignature(_ signature: Signature, forFileAt url: URL) throws -> Bool {
|
||||||
|
guard signature.signatureAlgorithm == .hashedEdDSA else { throw SignatureVerifyError.algorithmNotSupportedForFile }
|
||||||
|
var blake2b = try! BLAKE2b()
|
||||||
|
|
||||||
|
let fileHandle = try FileHandle(forReadingFrom: url)
|
||||||
|
|
||||||
|
let bufferSize = 4096
|
||||||
|
while true {
|
||||||
|
let data = fileHandle.readData(ofLength: bufferSize)
|
||||||
|
if data.isEmpty { break }
|
||||||
|
blake2b.update(data: data)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer { try? fileHandle.close() }
|
||||||
|
|
||||||
|
let digest = blake2b.finalize()
|
||||||
|
guard publicKey.isValidSignature(signature.signature, for: digest) else { return false }
|
||||||
|
let globalData = signature.signature + signature.trustedCommentData
|
||||||
|
guard publicKey.isValidSignature(signature.globalSignature, for: globalData) else { return false }
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum SignatureVerifyError: Error {
|
||||||
|
/// For ``PublicKey/isValidSignature(_:forFileAt:)``, only ``SignatureAlgorithm/hashedEdDSA`` algorithm is supported.
|
||||||
|
case algorithmNotSupportedForFile
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct Signature {
|
||||||
|
public let untrustedComment: String
|
||||||
|
public let signatureAlgorithm: SignatureAlgorithm
|
||||||
|
public let keyID: Data
|
||||||
|
public let signature: Data
|
||||||
|
public let trustedCommentData: Data
|
||||||
|
public let globalSignature: Data
|
||||||
|
|
||||||
|
public var trustedComment: String? {
|
||||||
|
return String(data: trustedCommentData, encoding: .utf8)
|
||||||
|
}
|
||||||
|
|
||||||
|
public init?<D>(text: D) where D: DataProtocol {
|
||||||
|
let lines = text.split(separator: UInt8(ascii: "\n"), maxSplits: 4, omittingEmptySubsequences: false)
|
||||||
|
guard lines.count == 4 || lines[4].isEmpty else { return nil }
|
||||||
|
|
||||||
|
guard lines[0].starts(with: untrustedCommentHeader) else { return nil }
|
||||||
|
guard
|
||||||
|
let untrustedComment = String(
|
||||||
|
data: Data(lines[0].suffix(from: untrustedCommentHeader.count as! D.Index)),
|
||||||
|
encoding: .utf8
|
||||||
|
)
|
||||||
|
else { return nil }
|
||||||
|
self.untrustedComment = untrustedComment
|
||||||
|
|
||||||
|
guard let decLine2 = Data(base64Encoded: Data(lines[1]), options: []) else { return nil }
|
||||||
|
guard decLine2.count == 74 else { return nil }
|
||||||
|
guard let sigAlgo = SignatureAlgorithm(rawValue: decLine2.prefix(2)) else { return nil }
|
||||||
|
self.signatureAlgorithm = sigAlgo
|
||||||
|
self.keyID = decLine2[2..<10]
|
||||||
|
self.signature = decLine2[10..<74]
|
||||||
|
|
||||||
|
guard lines[2].starts(with: trustedCommentHeader) else { return nil }
|
||||||
|
self.trustedCommentData = Data(lines[2]).suffix(from: trustedCommentHeader.count)
|
||||||
|
|
||||||
|
guard let decLine4 = Data(base64Encoded: Data(lines[3]), options: []) else { return nil }
|
||||||
|
guard decLine4.count == 64 else { return nil }
|
||||||
|
self.globalSignature = decLine4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,110 @@
|
||||||
import Testing
|
// SPDX-License-Identifier: MIT
|
||||||
@testable import Minisign
|
// Based on https://github.com/slarew/swift-minisign
|
||||||
|
// Copyright 2021 Stephen Larew, 2025 Shibo Lyu
|
||||||
|
|
||||||
@Test func example() async throws {
|
import Foundation
|
||||||
// Write your test here and use APIs like `#expect(...)` to check expected conditions.
|
import Minisign
|
||||||
|
import Testing
|
||||||
|
|
||||||
|
struct MinisignTests {
|
||||||
|
|
||||||
|
// password: test
|
||||||
|
static let privKey = """
|
||||||
|
untrusted comment: minisign encrypted secret key
|
||||||
|
RWRTY0Iyvmea6pdrXYdDVqn91GknFBllkJmsQyS2jpVGoBqETB4AAAACAAAAAAAAAEAAAAAAr5jLDlb+ahHMPoPZAawLCKbUilW5ECEFsFCFSQLXfKrFQDv54sYqJzr3rR4gTmDnplQY+/T+EYCZkc5+QJOWwmaKBHPRx+Tw3rFH4CfCGkYRr4WNdZprmAzi1ZNzTl/wyvc1/uplgO8=
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
static let pubKey = """
|
||||||
|
untrusted comment: minisign public key E28A983382D6D7E9
|
||||||
|
RWTp19aCM5iK4plw14gbtviwUSISZP++TJMfOfNTKoCcRIkcrV13Oppe
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
static let signature = """
|
||||||
|
untrusted comment: signature from minisign secret key
|
||||||
|
RWTp19aCM5iK4olS02BlgllVHi3lvR9OYUVu7gM/lMsTRsO2Qb1IBxJBt3xW14hAFZo7Zlceavr7u69Rt0Wk5wMX0ShF13DZygY=
|
||||||
|
trusted comment: timestamp:1629695994\tfile:test.pub
|
||||||
|
o4E++I6KyX1h3iYMQ5yNyqEfhphdrIXiFmnWarzbB1BQpsckcO1I3LLttzS1w2CjCEauKZ3bOeY//sYui8rbAQ==
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
static let badSignature = """
|
||||||
|
untrusted comment: signature from minisign secret key
|
||||||
|
RWTp19aCM5iK4olS02BlgllVHi3lvR9OYUVu7gM/lMsTRsO2Qb1IBxJBt3xW14hAFZo7Zlceavr7u69Rt0Wk5wMX0ShF13DZygY=
|
||||||
|
trusted comment: timestamp:1629695994\tfile:test.pu
|
||||||
|
o4E++I6KyX1h3iYMQ5yNyqEfhphdrIXiFmnWarzbB1BQpsckcO1I3LLttzS1w2CjCEauKZ3bOeY//sYui8rbAQ==
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
static let prehashedSignature = """
|
||||||
|
untrusted comment: signature from minisign secret key
|
||||||
|
RUTp19aCM5iK4qzCz7Z/Y4YGsKxamuPediRB9WhvHRWnrJFREb/m9TCwxQUlug1QMYMqgaEi3IGS0trOxy4xhCkS3D7ksjLEFQg=
|
||||||
|
trusted comment: timestamp:1629695918\tfile:test.pub
|
||||||
|
0sZUtAIqxCkdV8nQ5+bODUIX09QZS4ilrsCT6wjkTXhsMJ2cQKL0wYH3Km8ZGG46Q2OhOY8sPl+2DTLjvrMmBg==
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
static let badPrehashedSignature = """
|
||||||
|
untrusted comment: signature from minisign secret key
|
||||||
|
RUTp19aCM5iK4qzCz7Z/Y4YGsKxamuPediRB9WhvHRWnrJFREb/m9TCwxQUlug1QMYMqgaEi3IGS0trOxy4xhCkS3D7ksjLEFQg=
|
||||||
|
trusted comment: timestamp:1629695918\tfile:test.pu
|
||||||
|
0sZUtAIqxCkdV8nQ5+bODUIX09QZS4ilrsCT6wjkTXhsMJ2cQKL0wYH3Km8ZGG46Q2OhOY8sPl+2DTLjvrMmBg==
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
@Test func parse() {
|
||||||
|
let pubKey = PublicKey(text: Self.pubKey.data(using: .utf8)!)
|
||||||
|
#expect(pubKey != nil)
|
||||||
|
#expect(pubKey?.untrustedComment == "minisign public key E28A983382D6D7E9")
|
||||||
|
#expect(pubKey?.keyID == Data(base64Encoded: "6dfWgjOYiuI=")!)
|
||||||
|
#expect(pubKey?.signatureAlgorithm == .pureEdDSA)
|
||||||
|
let sig = Signature(text: Self.signature.data(using: .utf8)!)
|
||||||
|
#expect(sig != nil)
|
||||||
|
#expect(sig?.untrustedComment == "signature from minisign secret key")
|
||||||
|
#expect(sig?.trustedComment == "timestamp:1629695994\tfile:test.pub")
|
||||||
|
#expect(sig?.signatureAlgorithm == .pureEdDSA)
|
||||||
|
#expect(sig?.keyID == Data(base64Encoded: "6dfWgjOYiuI=")!)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test func signature() {
|
||||||
|
let pubKey = PublicKey(text: Self.pubKey.data(using: .utf8)!)
|
||||||
|
#expect(pubKey != nil)
|
||||||
|
let sig = Signature(text: Self.signature.data(using: .utf8)!)
|
||||||
|
#expect(sig != nil)
|
||||||
|
|
||||||
|
#expect(pubKey!.isValidSignature(sig!, for: Self.pubKey.data(using: .utf8)!))
|
||||||
|
#expect(!pubKey!.isValidSignature(sig!, for: Self.pubKey.data(using: .utf8)!.advanced(by: 1)))
|
||||||
|
|
||||||
|
let badSig = Signature(text: Self.badSignature.data(using: .utf8)!)
|
||||||
|
#expect(badSig != nil)
|
||||||
|
#expect(!pubKey!.isValidSignature(badSig!, for: Self.pubKey.data(using: .utf8)!))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test func prehashedSignature() {
|
||||||
|
let pubKey = PublicKey(text: Self.pubKey.data(using: .utf8)!)
|
||||||
|
#expect(pubKey != nil)
|
||||||
|
let phSig = Signature(text: Self.prehashedSignature.data(using: .utf8)!)
|
||||||
|
#expect(phSig != nil)
|
||||||
|
|
||||||
|
#expect(pubKey!.isValidSignature(phSig!, for: Self.pubKey.data(using: .utf8)!))
|
||||||
|
#expect(!pubKey!.isValidSignature(phSig!, for: Self.pubKey.data(using: .utf8)!.advanced(by: 1)))
|
||||||
|
|
||||||
|
let badPhSig = Signature(text: Self.badPrehashedSignature.data(using: .utf8)!)
|
||||||
|
#expect(badPhSig != nil)
|
||||||
|
#expect(!pubKey!.isValidSignature(badPhSig!, for: Self.pubKey.data(using: .utf8)!))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test func prehashedSignatureForFile() {
|
||||||
|
let pubKey = PublicKey(text: Self.pubKey.data(using: .utf8)!)
|
||||||
|
#expect(pubKey != nil)
|
||||||
|
let phSig = Signature(text: Self.prehashedSignature.data(using: .utf8)!)
|
||||||
|
#expect(phSig != nil)
|
||||||
|
|
||||||
|
let fileURL = URL.temporaryDirectory.appending(component: "SwiftMinisignTests-\(UUID())-test.pub")
|
||||||
|
defer { try? FileManager.default.removeItem(at: fileURL) }
|
||||||
|
|
||||||
|
try! Self.pubKey.data(using: .utf8)!.write(to: fileURL)
|
||||||
|
#expect(try! pubKey!.isValidSignature(phSig!, forFileAt: fileURL))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue