Attomus/attomus-otp
GitHub: Attomus/attomus-otp
这是一个用于安全生成TOTP和HOTP一次性密码的Swift和Kotlin库,解决了移动应用中双因素认证的实现问题。
Stars: 0 | Forks: 0
# for some, I need to add Chinese context. For example, in the examples, "Running" is translated to "运行", so for headings that are verbs or nouns, I translate the non-technical parts.
为 iOS/Swift 和 Android/Kotlin 实现的 TOTP (RFC 6238) 和 HOTP (RFC 4226)。
两个独立的引擎,共享相同的设计:遵循相同的 RFC 标准,相同的 `otpauth://` URI 解析行为,相同的数据模型,以及可互操作的备份格式。
由 [Attomus Signet](https://attomus.com/products/signet/) 使用 — 一款零云端、离线的 iOS 和 Android 认证器。
## 实现
| | Swift | Kotlin |
|---|---|---|
| 平台 | iOS 16+、macOS 13+、watchOS 9+、tvOS 16+、Linux | Android (JVM/API 26+) |
| 包 | `swift/` — Swift 包管理器 | `kotlin/` — Gradle |
| 模块 | `import AttomusOTP` | `import com.attomus.otp.*` |
| TOTP / HOTP | ✓ | ✓ |
| `otpauth://` URI 解析 | ✓ | ✓ |
| Base32 解码 | ✓ | ✓ |
| 可移植备份模式 | ✓ | —(在应用层消费) |
| HOTP 计数器完整性数据块 | ✓ | —(在应用层消费) |
备份格式和计数器数据块在 Swift 库中定义,并在下文记录。iOS 和 Android 的 Signet 应用程序都生产并消费相同的磁盘格式,确保了跨平台的备份互操作性。
## 要求
### Looking at the list, all seem to be technical terms or proper nouns. However, "AttomusOTP" might have a Chinese name, but since it's not specified, I'll keep it in English.
- Swift 5.9+
- iOS 16+ / macOS 13+ / watchOS 9+ / tvOS 16+
- Linux:通过 [swift-crypto](https://github.com/apple/swift-crypto) 运行的 Swift 5.9+
### To be consistent with the instruction, I should keep all these in English if they are technical jargon. But the user said "translate", so maybe for some, I need to provide the Chinese translation of the term.
- Kotlin 1.9+ / JVM 17+
- Android API 26+ (minSdk 26)
- 无额外依赖 — 使用标准库中的 `javax.crypto`
## 安装说明
### Swift 包管理器
```
dependencies: [
.package(url: "https://github.com/attomus/attomus-otp.git", from: "1.0.0")
]
```
### Let's see the examples again: 'Running Naabu' has "Running" translated, but "Naabu" kept. Similarly, 'Kubernetes Setup' has "Setup" translated.
```
dependencies {
implementation("com.attomus:attomus-otp-android:1.0.1")
}
```
## For standalone terms like "API", in the example 'API Reference', "API" is kept, but "Reference" is translated. So for a heading like "API", if it's just "API", perhaps I don't translate it, or I translate it as "API" which is commonly used in Chinese.
### In technical Chinese, "API" is often used as is, or sometimes translated as "应用程序接口", but the instruction says to keep it in English.
**Swift**
```
import AttomusOTP
let code = try TOTP.generate(
secret: secretBytes, // raw seed bytes, not Base32-encoded
algorithm: .sha1,
digits: 6,
period: 30,
at: Date()
)
// "048921" — zero-padded to the requested digit count
```
**Kotlin**
```
import com.attomus.otp.TOTP
import com.attomus.otp.OTPAlgorithm
val code = TOTP.generate(
secret = secretBytes, // raw seed bytes, not Base32-encoded
algorithm = OTPAlgorithm.SHA1,
digits = 6,
period = 30
)
// "048921" — zero-padded to the requested digit count
val remaining = TOTP.remainingSeconds(period = 30)
// seconds until the current code expires
```
### The instruction explicitly says: "Keep all professional terms, proper nouns, tool/library/framework names, and technical jargon in their original English form."
**Swift**
```
let code = try HOTP.generate(
secret: secretBytes,
algorithm: .sha1,
digits: 6,
counter: 42
)
```
**Kotlin**
```
import com.attomus.otp.HOTP
import com.attomus.otp.OTPAlgorithm
val code = HOTP.generate(
secret = secretBytes,
counter = 42L,
algorithm = OTPAlgorithm.SHA1,
digits = 6
)
```
### `otpauth://` URI 解析
**Swift**
```
let result = try parseOTPURI(
"otpauth://totp/Example%3Aalice%40example.com?secret=JBSWY3DPEHPK3PXP&issuer=Example"
)
// result.account.type == .totp
// result.account.issuer == "Example"
// result.account.label == "alice@example.com"
// result.account.digits == 6
// result.account.period == 30
// result.secretBytes — raw seed bytes, ready to pass to TOTP.generate
```
错误是类型化的 (`OTPURIError`) — 无需解析字符串。应用了完整的验证:密钥长度、数字位数、周期、算法、URI 结构和百分号编码。
**Kotlin**
```
import com.attomus.otp.OTPURIParser
val result = OTPURIParser.parse(
"otpauth://totp/Example%3Aalice%40example.com?secret=JBSWY3DPEHPK3PXP&issuer=Example"
)
// result.account.type == OTPType.TOTP
// result.account.issuer == "Example"
// result.account.label == "alice@example.com"
// result.account.digits == 6
// result.account.period == 30
// result.secret — raw seed bytes, ready to pass to TOTP.generate
```
错误是类型化的 (`OTPURIError`) — 与 Swift 实现具有相同的错误分类法。
### 可移植备份模式 *(Swift)*
该备份模式将账户及其原始种子字节序列化为 JSON 负载。它有意设计为无依赖(仅需 `Foundation`),因此任何平台都可以实现兼容的读取器或写入器。
```
// Export — produce the JSON payload for the application layer to encrypt
let jsonPayload = try encodeExportDocument(
accounts: accounts,
secrets: secretsByID // [UUID: Data] — raw seed bytes keyed by account ID
)
// jsonPayload is UTF-8 JSON — hand directly to your encryption layer
// Never write this to disk unencrypted
// Import — decode and validate a decrypted payload
let provisioningResults = try decodeExportDocument(jsonPayload)
for result in provisioningResults {
// result.account, result.secretBytes
}
```
此库定义了模式版本 1。应用层负责加密信封 — Signet 使用 Argon2id + AES-256-GCM。该模式已文档化,以便任何平台都能实现兼容的读取器。
### HOTP 计数器完整性数据块 *(Swift)*
一个 41 字节、受 HMAC-SHA256 保护的记录,用于防篡改的 HOTP 计数器存储。
```
// Encode — produce a 41-byte blob for storage
let blob = try encodeCounterBlob(counter: 42, integrityKey: key)
// layout: [version:1][counter:8 BE][hmac-sha256:32] = 41 bytes
// Verify — decode and verify, recovering the counter value
let counter = try verifyCounterBlob(blob, integrityKey: key)
```
`integrityKey` 必须为 32 字节。格式是固定的;Signet 的 iOS 和 Android 版本都生产和消费相同的 41 字节布局。HMAC 比较在全局范围内采用恒定时间(Swift:使用无提前退出的位异或累加器;Kotlin:使用 `MessageDigest.isEqual`)。
## 支持的算法
| 算法 | TOTP | HOTP |
|-----------|:----:|:----:|
| SHA-1 | ✓ | ✓ |
| SHA-256 | ✓ | ✓ |
| SHA-512 | ✓ | ✓ |
数字位数:6、7 或 8。TOTP 周期:30 秒和 60 秒。超出此范围的值将被拒绝。
## 安全性
- 两个实现都通过了所有 RFC 4226 (HOTP) 和 RFC 6238 (TOTP) 测试向量
- HMAC 比较在全局范围内采用恒定时间(Swift:使用无提前退出的位异或累加器;Kotlin:`MessageDigest.isEqual`)
- 任一库都不会记录、写入磁盘或在错误消息中捕获任何密钥
- 经过模糊测试:URI 解析器和备份模式解码器已通过数十亿次迭代测试,零崩溃
- Swift:`Sources/AttomusOTP` 仅使用 `Foundation` 和 `CryptoKit`(Apple 平台)或 `swift-crypto`(Linux)— 无其他依赖
- Kotlin:`com.attomus.otp` 仅使用 JVM 标准库中的 `javax.crypto`
- 任一实现都无需网络、存储或平台权限
## 许可证
[MIT](LICENSE) — 版权所有 (c) 2026 Attomus Ltd
标签:Android开发, Base32编码, HOTP算法, iOS开发, Kotlin库, RFC标准, Swift库, TOTP算法, URI解析, XML 请求, 一次性密码, 互操作性, 双因素认证, 安全开发, 安全认证, 密码学, 密码生成, 手动系统调用, 数据备份, 目录枚举, 离线认证, 移动安全, 认证器, 零云应用