{"id":170,"date":"2006-08-11T14:06:42","date_gmt":"2006-08-11T21:06:42","guid":{"rendered":"http:\/\/www.red-sweater.com\/blog\/170\/usable-keychain-scripting"},"modified":"2006-08-11T14:31:46","modified_gmt":"2006-08-11T21:31:46","slug":"usable-keychain-scripting","status":"publish","type":"post","link":"https:\/\/redsweater.com\/blog\/170\/usable-keychain-scripting","title":{"rendered":"Usable Keychain Scripting"},"content":{"rendered":"<style type=\"text\/css\"><!-- .caption { border-style:dashed; border-width:1px; border-color:#BBBBBB; margin-left:20px; padding:10px;}--><\/style>\n<p>\nAnybody who&#8217;s tried to use Apple&#8217;s Keychain Scripting has probably learned that its performance and functionality are both fatally flawed.\n<\/p>\n<p>\nThe quintessential flaw in Keychain Scripting&#8217;s performance can be observed by simply asking it to find a key by some attribute test. If it works, then it will take a long, long time. All of its &#8220;whose clause&#8221; functionality is extremely slow, but this simple case forces it to  go through each item in the keychain, failing to find a key:\n<\/p>\n<div class=\"caption\">\n<pre>\ntell application \"Keychain Scripting\"\n\tset myKey to first key of current keychain &not;\n\t\t\twhose name is \"zzzzz\"\nend tell\n<\/pre>\n<\/div>\n<p>\nJust how bad is it? I knew I had seen times of at least a minute, but I decided to test with Shark just to be sure. I let it rip and to my surprise AppleScript eventually gave up with a &#8220;event timed out&#8221; error. I stopped shark and observed that <strong>Keychain Scripting had used up 2.3 minutes of CPU time<\/strong> (!).\n<\/p>\n<p>\nI was anxious to learn how bad it could get so I put a &#8220;with timeout of 200000 seconds&#8221; around the AppleScript block and ran it again.  The pipes must have been warm this time, because Keychain Access came back in a &#8220;zippy&#8221; 1.3 minutes, finally having failed to locate the item as expected.\n<\/p>\n<p>\nObviously, Keychain Scripting is freaking useless.\n<\/p>\n<p>\nI decided to take a stab at writing my own, because I&#8217;ve been waiting too long for this to get fixed and I just don&#8217;t have any faith left. I figured it was a good opportunity to learn about the Security Framework, with which I have had no prior  experience.  I used the Keychain Access dictionary as scaffolding for everything I needed to implement, and slowly filled in the gaps, testing each attribute and command before and after implementation, learning the API as I went along. I abided by my policy of ignoring performance considerations until I got something working. Before long, I had completed set of simple Cocoa wrappers around the Security framework, which simply map through to live-fetches of the data from the underlying database.\n<\/p>\n<p>\nThe results? The script that takes (at best) 1.3 minutes to run in Keychain Access takes 300ms in &#8220;Usable Keychain Scripting.&#8221; Holy cow manure! That&#8217;s a 260x performance improvement, and I haven&#8217;t optimized anything. This fruit is so low-hanging it&#8217;s practically buried.\n<\/p>\n<p>\nOK, you might be thinking this is just an arbitrary example of a bad edge case. How does Keychain Scripting <em>really perform<\/em>? You know &#8230; when you&#8217;re looking for something that actually exists. Here&#8217;s another arbitrary example, this time collecting the keychain items that have my name in their name:\n<\/p>\n<div class=\"caption\">\n<pre>\ntell application \"Keychain Scripting\"\n\tset myKey to first key of current keychain &not;\n\t\t\twhose name contains \"daniel\"\nend tell\n<\/pre>\n<\/div>\n<p>\nThis time it&#8217;s 360ms in my Usable version, and uh oh, bad example, <em>simply doesn&#8217;t work<\/em> in Keychain Scripting.\n<\/p>\n<p><div class=\"caption\">\nKeychain Scripting got an error: Can&#8217;t get key 1 of current keychain whose name contains &#8220;daniel&#8221;.\n<\/div>\n<\/p>\n<p>\nUnusable. The same experience applies to most other reasonable attempts to ask it for information.\n<\/p>\n<p>\n<a href=\"http:\/\/www.red-sweater.com\/blog\/downloads\/UsableKeychainScripting.dmg\">Usable Keychain Scripting<\/a> is at least 260x better than Keychain Scripting in the speed of critical lookups, but there are other improvements, too. I fixed up the dictionary to not suck as much, and my code goes directly to the most modern security API, while the Apple version still goes through an outdated &#8220;KC&#8221; API. Who knows, one of these days maybe I&#8217;ll even optimize it. NOTE: the terminology is slightly different from Apple&#8217;s Keychain Scripting, but I think my terminology is clearer.\n<\/p>\n<p>\nSo why would you even want to script Keychain? Well, for one thing if you script Keychain instead of hardcoding passwords in your scripts, things are a lot more secure. Also, there are certain keys for which I find myself constantly going into Keychain Access and looking up the values for. Either Safari forgets how to auto-enter it, or NetNewsWire loses its wits about something. For instance, every once in a while my <a href=\"http:\/\/www.daringfireball.net\/\">Daring Fireball<\/a> subscriber feeds lose knowledge of their password. With the scripting mechanism working as it should, I can keep a short script attached to NNW for refetching it:\n<\/p>\n<div class=\"caption\">\n<pre>\ntell application \"Usable Keychain Scripting\" to tell current keychain\n\tset myPass to password of first internet password &not;\n\t\twhose protocol is HTTP and name is &not;\n\t\t\"daringfireball.net (&lt;my email address>)\"\nend tell\nset the clipboard to myPass\n<\/pre>\n<\/div>\n<p>\nNow the password is in my clipboard and I just paste it into the field as NNW requests.\n<\/p>\n<p>\nNote: I have a mechanism in place for setting values of keychain items, but I am wary of making it public yet because of the risk of data loss if I did something wrong. For now just enjoy the speedy access to your existing keychain data.\n<\/p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Anybody who&#8217;s tried to use Apple&#8217;s Keychain Scripting has probably learned that its performance and functionality are both fatally flawed. The quintessential flaw in Keychain Scripting&#8217;s performance can be observed by simply asking it to find a key by some attribute test. If it works, then it will take a long, long time. All of [&hellip;]<\/p>\n","protected":false},"author":10,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[14,7,15],"tags":[],"class_list":["post-170","post","type-post","status-publish","format-standard","hentry","category-apple","category-applescript","category-programming"],"_links":{"self":[{"href":"https:\/\/redsweater.com\/blog\/wp-json\/wp\/v2\/posts\/170","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/redsweater.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/redsweater.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/redsweater.com\/blog\/wp-json\/wp\/v2\/users\/10"}],"replies":[{"embeddable":true,"href":"https:\/\/redsweater.com\/blog\/wp-json\/wp\/v2\/comments?post=170"}],"version-history":[{"count":0,"href":"https:\/\/redsweater.com\/blog\/wp-json\/wp\/v2\/posts\/170\/revisions"}],"wp:attachment":[{"href":"https:\/\/redsweater.com\/blog\/wp-json\/wp\/v2\/media?parent=170"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/redsweater.com\/blog\/wp-json\/wp\/v2\/categories?post=170"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/redsweater.com\/blog\/wp-json\/wp\/v2\/tags?post=170"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}