设为首页 收藏本站
查看: 1731|回复: 0

[软件发布] WaxSealCore 1.01 释出,Mac 下的“钥匙串”服务编程接口

[复制链接]
累计签到:77 天
连续签到:1 天
发表于 2015-3-5 08:14:29 | 显示全部楼层 |阅读模式
3月21日 深圳 OSC 源创会开始报名罗,送华为海思开发板
  WaxSealCore 1.01 释出,改进内容包括:

  •   SupportsisInvisibleproperty for passphrase items
  •   SupportsisNegativeproperty for passphrase items
  •   Bug fixes
什么是 WaxSealCore
WaxSealCore 是一个受 Cocoa 设计影响的 OOP 框架,由 @开源中国真理部部长 用 Objective-C 编写。其对 OS X Keychain Services API 进行了面向对象封装,使得 Mac 开发者更容易地将 Keychain 机制融入到自己的 app 中。相对于 Apple 官方的 Keychain Services API 来说:

  •   完全面向对象
  •   API 风格和 Cocoa 非常接近,熟练的 Mac 开发者可以迅速上手
  •   支持基于 Unicode 字符搜索密码项
  •   详尽的文档支持
什么是 Keychain Services
OS X 和 iOS 开发者对“钥匙串 API”(Keychain Services API,为消歧义,下文都使用英文名称)应该都有所耳闻,计算机用户总是必须管理许多用户 ID 和密码,比如在浏览器中的 Twitter,Facebook,OSChina.net 等网站,以及 Evernote,Skype,Telegram 等桌面和移动 app 的登录密码。这些服务在你能够使用之前都需要通过密码来验证使用者的身份。因为密码繁杂,所以很多用户总是通过起一个非常简单非常容易记住的密码,并且为多个服务使用相同的密码来应付这件事(甚至将密码写在随手能够找到的小纸条上的也大有人在)。这些做法都大大削弱了密码的安全性。
所以在 OS X 和 iOS 中有一个被称为Keychain的机制(平时你可以通过 OS X 自带的Keychain Access应用访问系统中的 Keychain),Keychain 是一种具有特殊格式的文件类型(.keychain 文件),其是一个安全的加密容器,其本身可以使用一个主密码(master password)进行锁定,除了密码的拥有人,没有人能够访问这个加密容器中的任何内容。OS X 和 iOS 用户在访问一个新的网站时,就会被询问是否要保存网站的密码,以便下次自动登录,当用户点击“保存”时,用户的密码就是被保存到这个加密容器内,Keychain 会对你输入的密码进行高强度的加密,然后存储在其中,下次访问时通过解密密码既可以实现自动登录。
Keychain Services 是 Keychain 机制的编程接口。OS X/iOS 开发者在开发应用时,只需要调用这套中的函数,就可以将自己的应用中用到的密码存储到 OS X/iOS 的 Keychain 中,下次需要使用密码时可以直接从 Keychain 中进行获取而不必每次都让用户重新输入。除此之外,对于 Mac 开发者来说,你的应用还可以和其他应用共享同一个服务的密码。Keychain Services 是一个很方便的 API,它无需开发者自己实现一套密码管理机制。
  事实上,OS X 版的 Firefox 和 Thunderbird 就有一个广为诟病的问题,就是它们都使用自己实现的密码管理器而不使用 Keychain,这有两个弊端:

  •   OS X 用户习惯使用 Keychain 并建立了信任。如果提供自己的密码管理器,那么用户对它的信任度跟对你的信任度是一样的,一般来说不如他们对 Apple 公司的信任度。
  •   用户不能在你的应用程序之外访问密码。例如,Mac 版的 Chrome,Safari 和 Opera 就都能够共享 Web 的登录资料,因为它们都使用 Keychain,并且用户可以用 Keychain Access 应用来修改他们看到的密码。
  -- David Chisnall,Cocoa Programming Developer's Handbook
上面只是简单介绍了一下 Keychain 机制和它的 API,它们的功能远不止存取密码这么简单,只不过这些功能是最常用到的。Keychain Services 这套 API 很强大,但是缺点就是,它的接口是纯 C 的,丑陋,复杂,并且因为它是基于 Core Foundation 的,所以需要你手动管理内存(不像 Cocoa/Cocoa-Touch 可以利用引用计数和自动释放池),所以极易产生 bug。再加上 Keychain Services 的文档很古老,有很多错误都会无故地增大学习曲线,所以,最终,我实在受够它了,懒惰是程序员得美德,于是我找了一些开源的 Objective-C wrapper,这些 wrapper 虽然简化了使用,但是功能上要么太简陋(只能存取 generic password 和 Internet password,而没有实现 Access Control List 这类强大的功能),要么年代久远。所以决定自己写一个全特性的封装,而不仅是限于存取密码这种简单的功能。
WaxSealCore 和 Keychain Services 的比较
@红薯 说得好,框架的作者们不要总吹嘘自己的框架多么好用,而是要看你的框架能够实实在在地为开发者节省多少代码,所以用两个功能来比较一下 WaxSealCore 和纯 C 的 Keychain Services。

  •   使用一个显示指定的密码常见一个空的 Keychain
使用 Keychain Services 的纯 C 接口实现:
OSStatus resultCode = errSecSuccess;
SecKeychainRef secEmptyKeychain = NULL;
NSURL* URL = [ [ [ NSBundle mainBundle ] bundleURL ] URLByAppendingPathComponent: @"EmptyKeychainForWiki.keychain" ];
char* passphrase = "waxsealcore";
// Create an empty keychain with given passphrase
resultCode = SecKeychainCreate( URL.path.UTF8String
                              , ( UInt32 )strlen( passphrase )
                              , ( void const* )passphrase
                              , ( Boolean )NO
                              , NULL
                              , &secEmptyKeychain
                              );
NSAssert( resultCode == errSecSuccess, @"Failed to create new empty keychain" );
resultCode = SecKeychainDelete( secEmptyKeychain );
NSAssert( resultCode == errSecSuccess, @"Failed to delete the given keychain" );
if ( secEmptyKeychain )
    // Keychain Services is based on Core Foundation,
    // you have to manage the memory manually
    CFRelease( secEmptyKeychain );使用 WaxSealCore 实现:
NSError* error = nil;
// Create an empty keychain with given passphrase
WSCKeychain* emptyKeychain = [ [ WSCKeychainManager defaultManager ]
    createKeychainWithURL: [ [ [ NSBundle mainBundle ] bundleURL ] URLByAppendingPathComponent: @"EmptyKeychainForWiki.keychain" ]
               passphrase: @"waxsealcore"
           becomesDefault: NO
                    error: &error ];
// You have no need for managing the memory manually,
// emptyKeychain will be released automatically.

  •   查找下面截图中的这个密码项,并且获取它的账户名,密码和注释信息(注释信息含有中文,Keychain Services 无法进行查找)
DSC0000.png
使用 Keychain Services 的纯 C 接口实现:
OSStatus resultCode = errSecSuccess;
// Attributes that will be used for constructing search criteria
char* label = "secure.imdb.com";
SecProtocolType* ptrProtocolType = malloc( sizeof( SecProtocolType ) );
*ptrProtocolType = kSecProtocolTypeHTTPS;
SecKeychainAttribute attrs[] = { { kSecLabelItemAttr, ( UInt32 )strlen( label ), ( void* )label }
                               , { kSecProtocolItemAttr, ( UInt32 )sizeof( SecProtocolType ), ( void* )ptrProtocolType }
                               };
SecKeychainAttributeList attrsList = { sizeof( attrs ) / sizeof( attrs[ 0 ] ), attrs };
// Creates a search object matching the given list of search criteria.
SecKeychainSearchRef searchObject = NULL;
if ( ( resultCode = SecKeychainSearchCreateFromAttributes( NULL
                                                         , kSecInternetPasswordItemClass
                                                         , &attrsList
                                                         , &searchObject
                                                         ) ) == errSecSuccess )
    {
    SecKeychainItemRef matchedItem = NULL;
    // Finds the next keychain item matching the given search criteria.
    while ( ( resultCode = SecKeychainSearchCopyNext( searchObject, &matchedItem ) ) != errSecItemNotFound )
        {
        SecKeychainAttribute theAttributes[] = { { kSecAccountItemAttr, 0, NULL }
                                               , { kSecCommentItemAttr, 0, NULL }
                                               };
        SecKeychainAttributeList theAttrList = { sizeof( theAttributes ) / sizeof( theAttributes[ 0 ] ), theAttributes };
        UInt32 lengthOfPassphrase = 0;
        char* passphraseBuffer = NULL;
        if ( ( resultCode = SecKeychainItemCopyContent( matchedItem
                                                      , NULL
                                                      , &theAttrList
                                                      , &lengthOfPassphrase
                                                      , ( void** )&passphraseBuffer
                                                      ) ) == errSecSuccess )
            {
            NSLog( @"\n==============================\n" );
            NSLog( @"Passphrase: %@", [ [ [ NSString alloc ] initWithBytes: passphraseBuffer length: lengthOfPassphrase encoding: NSUTF8StringEncoding ] autorelease ] );
            for ( int _Index = 0; _Index < theAttrList.count; _Index++ )
                {
                SecKeychainAttribute attrStruct = theAttrList.attr[ _Index ];
                NSString* attributeValue = [ [ [ NSString alloc ] initWithBytes: attrStruct.data length: attrStruct.length encoding: NSUTF8StringEncoding ] autorelease ];
                if ( attrStruct.tag == kSecAccountItemAttr )
                    NSLog( @&quot;IMDb User Name: %@&quot;, attributeValue );
                else if ( attrStruct.tag == kSecCommentItemAttr )
                    NSLog( @&quot;Comment: %@&quot;, attributeValue );
                }
            NSLog( @&quot;\n==============================\n&quot; );
            }
        SecKeychainItemFreeContent( &theAttrList, passphraseBuffer );
        CFRelease( matchedItem );
        }
    }
if ( ptrProtocolType )
    free( ptrProtocolType );
if ( searchObject )
    CFRelease( searchObject );使用 WaxSealCore 实现:
只需一个方法的调用即可实现:
NSError* error = nil;
WSCPassphraseItem* IMDbLoginPassphrase = ( WSCPassphraseItem* )[ [ WSCKeychain login ]
    findFirstKeychainItemSatisfyingSearchCriteria: @{ WSCKeychainItemAttributeLabel : @&quot;secure.imdb.com&quot;
                                                    , WSCKeychainItemAttributeProtocol : WSCInternetProtocolCocoaValue( WSCInternetProtocolTypeHTTPS )
                                                    , WSCKeychainItemAttributeComment : @&quot;这是一个用于演示 WaxSealCore 的密码项&quot;
                                                    }
                                        itemClass: WSCKeychainItemClassInternetPassphraseItem
                                            error: &error ];
// WaxSealCore supports Unicode-based search, so you can use Emoji or Chinese in your search criteria.
// One step. So easy, is not it?打印账户名,密码,和注释,并且更改注释内容:
if ( IMDbLoginPassphrase )
    {
    NSLog( @&quot;==============================&quot; );
    // Use the `account` property
    NSLog( @&quot;IMDb User Name: %@&quot;, IMDbLoginPassphrase.account );
    // Use the `passphrase` property
    NSLog( @&quot;Passphrase: %@&quot;, [ [ [ NSString alloc ] initWithData: IMDbLoginPassphrase.passphrase encoding: NSUTF8StringEncoding ] autorelease ] );
    // Use the `comment` property
    NSLog( @&quot;Comment: %@&quot;, IMDbLoginPassphrase.comment );
    NSLog( @&quot;==============================&quot; );
    // -setComment:
    IMDbLoginPassphrase.comment = @&quot;IMDb Passphrase&quot;;
    }
else
    NSLog( @&quot;I'm so sorry!&quot; );简单地进行批量搜索:
// Find all the Internet passphrases that met the given search criteria
NSArray* passphrases = [ [ WSCKeychain login ]
    // Batch search
    findAllKeychainItemsSatisfyingSearchCriteria: @{ WSCKeychainItemAttributeLabel : @&quot;secure.imdb.com&quot;
                                                   , WSCKeychainItemAttributeProtocol : WSCInternetProtocolCocoaValue( WSCInternetProtocolTypeHTTPS )
                                                   , WSCKeychainItemAttributeComment : @&quot;IMDb Passphrase&quot;
                                                   }
                                       itemClass: WSCKeychainItemClassInternetPassphraseItem
                                           error: &error ];
if ( passphrases.count != 0 )
    {
    for ( WSCPassphraseItem* _Passphrase in passphrases )
        {
        NSLog( @&quot;==============================&quot; );
        NSLog( @&quot;IMDb User Name: %@&quot;, IMDbLoginPassphrase.account );
        NSLog( @&quot;Passphrase: %@&quot;, [ [ [ NSString alloc ] initWithData: IMDbLoginPassphrase.passphrase encoding: NSUTF8StringEncoding ] autorelease ] );
        NSLog( @&quot;Comment: %@&quot;, IMDbLoginPassphrase.comment );
        NSLog( @&quot;==============================&quot; );
        _Passphrase.comment = @&quot;这是一个用于演示 WaxSealCore 的密码项&quot;;
        }
    }
else
    NSLog( @&quot;I'm so sorry!&quot; );上面的演示可以看到,使用 Keychain Services 费很大力气需要完成的工作,用 WaxSealCore 寥寥几行代码即可做到。除此之外,WaxSealCore 还简化了 Keychain 中的 Access Control List 机制,你可以更容易地使用 Keychain 更强大的功能。更多 API 的使用方式,可以参考我正在维护的一个 Wiki,欢迎任何人来编辑这个 wiki 页面。
WaxSealCore 是自由软件,在 MIT 许可证下发布,你可以在这里获取源码,自由修改或重新分发源代码。如果不想自己编译代码,可以在这里获取到我用我的开发者证书签名的二进制框架包。
Next Step
Keychain Services 不仅仅能够存取普通密码,同时还能够存取数字证书(digital certificates),私钥(private keys)等私密数据,WaxSealCore 下一个版本就要提供对跟 Keychain Services 同处于 Security.framework 框架中的Certificate, Key, and Trust ServicesAPI 的封装,将融合对数字证书,对称密钥和非对称密钥的存取与操作,敬请期待。
获取 WaxSealCore

  •   二进制下载
  •   获取源码或进行贡献
  •   在线文档
  •   适用于 Dash 和 Xcode 文档浏览器的离线文档包
联系作者
如果你有任何问题:

  •   给我发邮件Tong-G@outlook.com
  •   在 Twitter 上 DM 我:@NSTongG
  •   如果你使用 S/MIME 加密邮件,可以在这里获取我的 S/MIME 证书以及和其相关联的中间证书然后给我发送加密邮件
  •   如果你使用 GnuPG,可以给我发送 PGP 加密邮件,我的 GnuPG 公钥是0x5604FA90,你可以在公钥服务器上 retrieve 之

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-43513-1-1.html 上篇帖子: AppCode 3.1.4 发布,Objective-C 集成开发环境 下篇帖子: PostgreDAC 3.0 发布,PG 的 Delphi 组件
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表