代码之家  ›  专栏  ›  技术社区  ›  greg

Keychain Services安全说明

  •  8
  • greg  · 技术社区  · 10 年前

    Keychain Services API的文档还有一点需要改进。我似乎找不到的一件事是访问Keychain Access应用程序允许您添加和编辑的Secure Notes的详细信息。

    如有任何见解,将不胜感激。谢谢

    3 回复  |  直到 10 年前
        1
  •  11
  •   mgrandi    10 年前

    只是为了扩展公认的答案:

    实际上,“安全笔记”只是作为特殊格式的通用密码存储的。因此,如果您创建了一个安全注释,则可以使用 Keychain Services API: SecKeychainFindGenericPassword() security command line tool .

    作为使用的示例 安全 ,如果您有名为“测试说明”的安全说明:

    showing the note in keychain access

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

    因此,您可以使用此命令搜索类型为“secure note”、标题为“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"
    

    要获得要输出的密码,还需要传递 -g 选项 安全 命令,除非您已显式设置 安全 作为一个受信任/允许访问该钥匙链项目的程序,它将询问您是否希望允许访问钥匙链项目:

    dialog asking if you want to allow access to keychain item

    仅查看密码输出(您可以使用 -w 选项仅输出“密码”或注释文本,但您不会得到“解码”输出,只有十六进制),您将得到:

    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就是这样存储字典的),但“RTF”密钥是什么?用二进制代码看它会给人一种感觉 rtfd file :

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

    但将其保存为.rtfd不起作用,但后来我意识到,例如,从TextEdit保存的RTF是捆绑包!那么这是如何工作的。。。您不能真正将捆绑包序列化为字节,因为它是一个包含文件的文件夹,但是经过进一步搜索,(我发现 Apple Type Code list ,还有“com.apple.rtfd”,但也有“com.apple.flat-rtfd”!

    所以我用了 sample application from Apple 显示有关剪贴板/粘贴板的详细信息。然后,您可以右键单击Keychain访问,“复制安全注释”:

    copy secure note in keychain access

    然后,如果您查看ClipboardViewer中的字节,就会发现它与plist中标记中的非十六进制字节相匹配。

    呼!这比我预期的要长得多。。。。因此,简而言之,Secure Note只是一个通用密码,带有标题,密码部分是Apple XML Plist,带有明文数据,以及适合于使用“Copy Secure Note to clipboard”复制到剪贴板的粘贴板格式的数据。

    我希望这能澄清安全笔记的存储方式,因为确实缺少访问安全笔记的API函数,而官方Keychain访问API中没有任何内容。

        2
  •  8
  •   greg    10 年前

    我发现你可以使用安全命令行工具提取数据。安全注释存储为具有以下特征的通用密码:

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

    type<uint32>="note" -您可以在搜索时(使用-C标志)使用它来识别安全笔记。

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

    0x00000007 <blob>= "Note name" -我不知道你是否可以通过API获得,但你肯定可以通过命令行工具获得

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

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

        3
  •  6
  •   Stefan Haberl    3 年前

    您可以从macOS终端使用一长串命令获取密钥链安全注释的值。下面的代码段获取名为“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