钥匙串服务安全笔记

8

Keychain Services API的文档留下了一些不足之处。我找不到的一个事情是如何访问Keychain Access应用程序所允许添加和编辑的安全笔记的详细信息。

任何见解都将不胜感激。谢谢。


1
根据苹果文档中的“钥匙串服务概念”部分,"笔记通常是由用户使用钥匙串访问实用程序输入的"。换句话说,这听起来像是一些苹果工程师在Keychain Access中实现了一个半成品的想法,但从未考虑过为开发人员提供一个周密的安全笔记API。 - Michael Dautermann
这基本上是我在一些相当晦涩的参考资料中发现的。 我在文档中找不到任何具体的东西。 谢谢反馈。 - greg
4个回答

12

仅就已接受答案进行扩展:

确实,“安全笔记”仅作为格式化的通用密码存储。因此,如果您创建了一个安全笔记,可以使用Keychain Services API:SecKeychainFindGenericPassword()security命令行工具进行编程访问。

以使用security为例,如果你有一个名为“测试笔记”的安全笔记:

showing the note in keychain access

您将需要搜索“安全笔记”和笔记标题“Testing Note”。 "类型"(或desc字段)将是“note”,而“服务”(或svce字段,密钥链条目的名称)将是笔记的实际标题。似乎对于您指定的每个字段,它都必须是精确的,因此搜索“Testing *”或“Testing”将不会返回我们笔记的任何结果。

所以您可以使用这个命令来搜索类型为“安全笔记”且标题为“Testing Note”的笔记:

security find-generic-password -C note -s "Testing Note"

然后您将得到以下结果:

keychain: "/Users/USERNAME/Library/Keychains/login.keychain"
class: "genp"
attributes:
    0x00000007 <blob>="Testing Note"
    0x00000008 <blob>=<NULL>
    "acct"<blob>=<NULL>
    "cdat"<timedate>=0x32303134313231323137333130395A00  "20141212173109Z\000"
    "crtr"<uint32>=<NULL>
    "cusi"<sint32>=<NULL>
    "desc"<blob>="secure note"
    "gena"<blob>=<NULL>
    "icmt"<blob>=<NULL>
    "invi"<sint32>=<NULL>
    "mdat"<timedate>=0x32303134313231323137333130395A00  "20141212173109Z\000"
    "nega"<sint32>=<NULL>
    "prot"<blob>=<NULL>
    "scrp"<sint32>=<NULL>
    "svce"<blob>="Testing Note"
    "type"<uint32>="note"

要想输出密码,您还需要向security命令传递-g选项。除非您已将security明确设置为允许访问该钥匙串项目的受信任/允许程序,否则它将询问您是否允许访问钥匙串项目:

dialog asking if you want to allow access to keychain item

如果只查看密码输出(您可以使用-w选项仅输出“password”或我们备注的文本,但是您无法获得“解码”输出,只会得到十六进制),则可使用以下命令:

security find-generic-password -C note -s "Testing Note" -w

(已进行格式化以供清晰阅读)

3c3f786d 6c207665 7273696f 6e3d2231 2e302220 656e636f
64696e67 3d225554 462d3822 3f3e0a3c 21444f43 54595045
20706c69 73742050 55424c49 4320222d 2f2f4170 706c652f
2f445444 20504c49 53542031 2e302f2f 454e2220 22687474
703a2f2f 7777772e 6170706c 652e636f 6d2f4454 44732f50
726f7065 7274794c 6973742d 312e302e 64746422 3e0a3c70
6c697374 20766572 73696f6e 3d22312e 30223e0a 3c646963
....... (and so on)

不是很有用!如果我们使用某些Python代码对其进行解码(或您选择的任何语言):

#!/usr/bin/env python3
import xml.etree.ElementTree as ET
import plistlib, pprint, binascii

# not full hex string for brevity!
hex_data = '''3c3f786d6c2076657273696f6e3d22312e3022206....'''

# decode hex into bytes
xml_bytes = binascii.unhexlify(hex_data)

# create ElementTree object since its an XML PList
ET.fromstring(xml_bytes)

# print out xml
print(ET.tostring(xml_bytes))

# or you can load it straight into a python object using plistlib
plist_dict = plistlib.loads(xml_bytes)
pprint.pprint(plist_dict)

现在我们有了进展!对其进行解码的结果为:

<plist version="1.0">
<dict>
    <key>NOTE</key>
    <string>12345
abcdefghijklmnopqrstuvwxyz
HELLO WORLD
=)
</string>
    <key>RTFD</key>
    <data>
    cnRmZAAAAAADAAAAAgAAAAcAAABUWFQucnRmAQAAAC43AQAAKwAAAAEAAAAvAQAAe1xy
    dGYxXGFuc2lcYW5zaWNwZzEyNTJcY29jb2FydGYxMzQzXGNvY29hc3VicnRmMTYwCntc
    Zm9udHRibFxmMFxmc3dpc3NcZmNoYXJzZXQwIEhlbHZldGljYTt9CntcY29sb3J0Ymw7
    XHJlZDI1NVxncmVlbjI1NVxibHVlMjU1O30KXHBhcmRcdHg1NjBcdHgxMTIwXHR4MTY4
    MFx0eDIyNDBcdHgyODAwXHR4MzM2MFx0eDM5MjBcdHg0NDgwXHR4NTA0MFx0eDU2MDBc
    dHg2MTYwXHR4NjcyMFxwYXJkaXJuYXR1cmFsCgpcZjBcZnMyNCBcY2YwIDEyMzQ1XAph
    YmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5elwKSEVMTE8gV09STERcCj0pXAp9AQAAACMA
    AAABAAAABwAAAFRYVC5ydGYQAAAAXSaLVLYBAAAAAAAAAAAAAA==
    </data>
</dict>
</plist>

显然,我们将明文密码作为“NOTE”键的值(因为这就是plist存储字典的方式),但“RTFD”键是什么呢?从二进制角度来看,它给人的印象是某种rtfd文件

b'rtfd\x00\x00\x00\x00\x03\x00\x00\x00\x02\x00\x00\x00\x07\x00\x00\x00TXT.rtf\x01 ......

但将其保存为.rtfd格式不起作用,但后来我意识到,例如从TextEdit保存的RTFD是一种束!那么这是如何工作的……您实际上无法将束序列化为字节,因为它是一个带有文件的文件夹,但在进一步搜索后,(我找到了Apple Type Code列表,其中有“com.apple.rtfd”,但也有“com.apple.flat-rtfd”,它说是“粘贴板”格式!

所以我使用了一个来自苹果的示例应用程序,该应用程序显示有关剪贴板/粘贴板的详细信息。然后,您可以在钥匙串访问中右键单击“复制安全笔记”:

copy secure note in keychain access

然后,如果您查看ClipboardViewer中的字节,则会发现它与plist中未加密的字节匹配。

哇!这比我预期的要长得多....因此,简而言之,安全笔记只是通用密码,具有标题,密码部分是Apple XML Plist,并且明文数据以适合复制到剪贴板的粘贴板格式中的数据形式存在,“将安全笔记复制到剪贴板”。

希望这解释了安全笔记的存储方式,因为确实缺少访问安全笔记的API函数,并且官方钥匙串访问API中没有任何内容。


哇,这太棒了,但是...也许我有点慢...你怎么能将未加密的数据导出为包含嵌入式图像的rtfd文件呢?我需要导出我的钥匙串数据库。其中某些内容已经损坏,找到它很困难。我只需要导出并开始一个新的钥匙串。我会把导出文件放在安全磁盘上,但有时我会懒得截屏密码并将其放在安全笔记中。我应该只有几个,但我不知道哪些是哪些。如果无论内容如何都可以导出整个东西就好了。 - hepcat72
@hepcat72 我认为KeychainAccess.app不允许您插入图像,我的意思是理论上您可以自己对图像进行base64编码,但这非常hacky。还有其他程序,如1Password或keypassX,可以处理附件,因此您可以上传图像和其他文件。 - mgrandi
我已经在我的钥匙串访问数据库中保存了图像。很久以前,我使用钥匙串访问应用程序添加了它们。该应用程序使用rtfd,它被存储为平面XML文件(包括编码图像)。RTFD文件支持附件,因此密钥链访问也支持它们。你可以尝试一下。只需将图像拖到密钥串访问中的安全注释中。我只是在寻找一种导出图像以及我的数据库中其他所有内容的方法。无论如何,关于我的问题,我只是通过使用安全命令行工具根据条目大小来识别屏幕截图信息。 - hepcat72
哦,有趣,我不知道你可以将图像拖放到其中,这肯定不直观。我会回复你的! - mgrandi
哦,如果你不想拖放或复制粘贴(顺便说一句,这也是可行的),你该如何将图像放入文档中呢? - hepcat72
此外,RTFD 的内容包括字体大小、颜色和样式等格式设置,实际上还有各种各样的东西:行间距等。通常,带有 .rtfd 扩展名的文件是一个目录,您可以右键单击它以显示包内容。我不知道要导出具有格式和嵌入图像/文件的完整 rtfd 文件需要做什么。如果您弄清楚了,请告诉我。 - hepcat72

8

我发现您可以使用安全命令行工具来提取数据。安全笔记以以下特点存储为通用密码:

class: "genp" - 这与通用密码相同

type<uint32>="note" - 搜索时可以使用此标识符专门识别安全笔记(使用-C标志)。

desc<blob>="secure note" - 我不知道是否可以根据此字段搜索,但它确实将项目标识为安全笔记

0x00000007 <blob>= "Note name" - 我不知道是否可以通过API获取此信息,但是您可以从命令行工具中得到它

acct<blob>=<NULL> - 这似乎是安全笔记的常见特征

使用命令security dump-keychain查找有关钥匙串项目的所有有用信息。


7

您可以使用一长串从MacOS终端中的命令来获取keychain安全笔记的值。以下片段获取名为“foobar”的笔记的值,并将其保存到名为foobar.txt的文件中,位于用户桌面上。

security find-generic-password -C note -s 'foobar' -w | xxd -r -p | 
 xmllint --xpath "//dict/data/text()" - | base64 --decode | 
 textutil -stdin -convert txt -output ~/Desktop/foobar.txt

1
这应该是被接受的答案。@mgrandi解释了涉及的内部细节,但这个答案提供了所有必要的实际命令来回答OP的问题。 - Stefan Haberl

0
我最近有这个需求,然后找到了这个问题。它让我走上了正确的轨道,但我使用了以下方法:
$h = security find-generic-password -a AAAAA -s BBBBB -w
$k = -join (($h | sls '(..)' -a).matches.value | %{[char][int]"0x$_" })
$k

非常简洁,但它正在使用 select-string (sls) 对所有 (-a) 正则表达式匹配组进行匹配,使用任意 2 个字符 ('(..)'),然后我们只获取匹配本身的值,这将是一个数组总和,并将其传递到循环中,通过使用一些 0x 快捷方式将十六进制转换为字符值,最后将所有内容连接在一起。由于我们只是将它们压缩在一起,因此可以将 -join 移动到开头,而不是在结尾处执行 -join ''。

我通常不会这么简洁,但这对我的需求来说是一种边缘情况,我宁愿它短小精悍。我只想将一个大值存储为我的 Mac 上的注释,并在需要时使用它,而不是使用环境变量。我的需求更多是一次性的,但在生产环境中,它可能只是一个环境变量或“从保险库获取”类型的情况,因此这只是在我的 Mac 上摆弄的结果。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接