Skip to content

调研:从 1Password 和 Apple 密码迁移(2026-11-16) ​

结论先说:

  • Apple 密码用 CSV 就够了。
  • 1Password 走 .1pux。
  • 通行密钥(passkey)只能经 FIDO Credential Exchange(CXF/CXP)迁移,而且接收方必须是签名过的原生 App,带 AutoFill credential provider 扩展。

1Password .1pux ​

压缩包结构: 一个账户导出一个 <accountUUID>.1pux,是 zip 包,里面有:

  • export.attributes,内容形如 {"version":3,"description":"1Password Unencrypted Export","timestamp":…}。官方文档写的字段名是 createdAt,实际样本里是 timestamp。
  • export.data,JSON 正文。
  • files/,存附件,命名为 files/<documentId>__<fileName>。

JSON 结构: accounts[] → vaults[] → items[]。

  • 保险库类型:P 个人、E 所有人、U 用户自建。
  • 条目 UUID 只在所在保险库内唯一。
  • 条目字段:uuid、favIndex、createdAt/updatedAt(Unix 秒)、state(active 或 archived)、categoryUuid。
  • overview:title、url、urls[{label,url}]、tags[]。
  • details:loginFields、notesPlain、sections、passwordHistory[{value,time}]、documentAttributes、password(仅「密码」类别)。

类别编号:

编号类别编号类别
001Login104OutdoorLicense
002CreditCard105Membership
003SecureNote106Passport
004Identity107RewardsProgram
005Password108SSN
006Document109WirelessRouter
100SoftwareLicense110Server
101BankAccount111EmailAccount
102Database112API_Credential
103DriversLicense113MedicalRecord
114SSH_Key

字段:

  • loginFields 由 value、fieldType、designation(username / password)组成。fieldType 取值为 T、E、U、N、P、A、TEL、C。
  • sections[].fields[] 结构为 {title,id,value:{<类型>:…},guarded,multiline}。类型有:string、concealed、totp(裸密钥或 otpauth://,可以有多个)、url、email、phone、date、monthYear、menu、address、creditCardType、creditCardNumber、reference、sshKey(PKCS#8 + 公钥 + 指纹)、file。

限制:

  • 桌面版导出不含通行密钥。1Password 只在 iOS 26+ 和 Android 14+ 上支持经 CXP 导出通行密钥。
  • 1Password 的 CSV 导出只有登录和密码两类,没有自定义字段和附件。

现有导入器(都是 GPL,只能参考,不能复制) ​

导入器范围丢失的内容
Bitwarden libs/importer/.../onepassword-1pux-importer.ts只读第一个账户保险库结构、附件、多余的 TOTP、多余的标签
KeePassXC src/format/OPUXReader.cpp只读第一个账户;覆盖最全:保险库变组,所有标签、URL、TOTP 和附件都保留密码历史
Proton Pass 1pux.reader.ts读所有账户把「已归档」当成「已删除」

Apple 密码 ​

CSV 表头: Title,URL,Username,Password,Notes,OTPAuth。旧版 Safari 导出的表头是 Title,Url,Username,Password。

CSV 里导不出的内容:

  • Apple 官方说明导不出的:Wi-Fi 密码、别人共享给你的群组密码、通过 Apple 登录的账户。
  • 第三方资料提到、Apple 未确认的:通行密钥、第一个之后的其余 URL、分组。

Credential Exchange(macOS / iOS 26 起):

  • 用 ASCredentialImportManager。
  • 接收方条件:
    • App 带 AutoFill credential provider 扩展。
    • 扩展的 Info.plist 里设 SupportsCredentialExchange = YES、SupportedCredentialExchangeVersions = ["1.0"]。
    • NSUserActivityTypes 包含 ASCredentialExchangeActivityType。
    • 启动时读 ASCredentialImportToken,再调用 importCredentials(token:)。
  • 只能由导出方发起,全程不落地成文件。
  • 支持的类型:basicAuthentication、passkey、totp、note、creditCard、apiKey、address、customFields、driversLicense、generatedPassword、identityDocument、passport、personName、sshKey、wifi。没有文件类型,所以附件迁不过来。

FIDO CXF / CXP ​

  • CXF 1.0 是 Proposed Standard(2026-03 有勘误);CXP 还是工作草案。Apple 用它自己的系统通道传 CXF 数据。
  • bitwarden/credential-exchange:MIT 许可,crate 是 credential-exchange-format,版本 0.4.0。覆盖所有 CXF 类型,但仍处在早期开发阶段,也没有内置 zeroize。可以作为依赖使用。
  • bitwarden/sdk-internal 的 bitwarden-exporters/src/cxf/ 带有真实的 1Password 和 Dashlane CXF 样本,但它是 GPL,只能参考。

通用字段映射 ​

通用字段1puxApple CSVCXF
titleoverview.titleTitleitem.title
urls[]overview.urls[].urlURL(只有一个)scope.urls / rpId
username/passwordloginFields 里的 designation → 名为 username/password 的分区字段 → details.passwordUsername/Passwordbasic-auth
totp[]value.totpOTPAuthtotp
notesnotesPlainNotesnote
自定义字段sections + 其余 loginFields–custom-fields
附件files/ + documentAttributes–file(Apple API 不支持)
容器vault–collection
标签/收藏/归档tags/favIndex/state–tags/favorite
历史passwordHistory––
通行密钥––passkey

实施建议 ​

  1. 1Password: 自己用 Rust 写 1pux 解析器。读全部账户;保险库映射成容器;所有标签、URL、TOTP、附件、历史、归档状态和带类型的字段都保留;映射不了的字段放进自定义字段,一律不丢。
  2. Apple: v1 用 CSV。通行密钥等 macOS / iOS 原生 App 带上 provider 扩展后再走 CXF。
  3. 核心库: 只写一个 CXF 到内部模型的映射,基于 credential-exchange-format,配合 zeroize。平台层只负责传 JSON。
  4. 需要人做的: 导出真实的测试样本。CXP 测试还需要 Apple Developer 签名。

文档对应提交 80b7c2d · 由仓库 docs/ 自动生成