-
-
Save symposion/1289716 to your computer and use it in GitHub Desktop.
These two files should help you to import passwords from mac OS X keychains to 1password. | |
Assumptions: | |
1) You have some experience with scripting/are a power-user. These scripts worked for me | |
but they haven't been extensively tested and if they don't work, you're on your own! | |
Please read this whole document before starting this process. If any of it seems | |
incomprehensible/frightening/over your head please do not use these scripts. You will | |
probably do something Very Bad and I wouldn't want that. | |
2) You have ruby 1.9.2 installed on your machine. This comes as standard with Lion, previous | |
versions of OS X may have earlier versions of ruby, which *may* work, but then again, they | |
may not :-) You can check by opening the terminal application and typing ruby -v | |
3) *THIS IS IMPORTANT* None of your passwords, usernames or site names contains a comma. It's | |
highly unlikely that a site name will contain a comma, fairly unlikely that usernames will, | |
but eminently possible that your passwords might. If they do, this script *will not work* | |
as supplied. You can modify it to quote all the values (there's a function for this already | |
in the script) before it outputs them, but beware: if any of your passwords contains a " | |
character it will break if you do this. If you have both quotes and commas in your passwords, | |
well, damn, you're fresh out of luck. The best you can do is to find the passwords with commas | |
in and remove them manually from the exported keychain (I'll mention where to do this below) | |
Instructions: | |
0) Save keychain.rb and click_allow.scpt in your home directory. | |
1) Enable full GUI scripting by going to the Universal Access System Preference Pane | |
and checking "Enable access for assistive devices" | |
2) Open the Terminal application and run the following command: | |
security dump-keychain -d login.keychain > keychain.txt | |
(If you have multiple keychains you should repeat this whole process once from step 2 onwards for | |
each one. You will have to change 'login.keychain' to 'foo.keychain' or somesuch.) | |
3) When you run the above command, the system will ask for permission to use your keychain. If you | |
have a separate keychain password/have paranoid settings on your keychain, you may need to enter | |
a password now. Otherwise, you will be presented with a dialog box asking you whether you want to | |
allow permission to access the first item in your keychain. You will be asked this once for every | |
item in your keychain (zzz). This is where the other file comes in: | |
4) Find the click_allow.scpt in your home directory using Finder, double click it. It will open in | |
the AppleScript editor. Click the run button. If all is well, the script will click the "Allow" | |
button for you lots of times until all of your keychain entries have been exported. Shouldn't | |
take more than a few minutes even for hundreds of entries. | |
5) When that finishes, go back to the Terminal window and run the following command: | |
ruby keychain.rb keychain.txt | sort > keychain.csv | |
6) If all is well, that command will finish very quickly without any message. If it spouts an error | |
at you, sorry, you'll have to fix the script, something's broken. Otherwise you should try opening | |
up keychain.csv in your favourite text editor (TextEdit? <shiver>) to make sure it contains a list | |
of keychain entries. Now is the time to search for passwords containing a comma (you may need regular | |
expressions to do this if you have a lot of keychain entries, since it's a comma-separated file) | |
and delete them to stop them hosing the 1password import. You'll have to enter these manually, hopefully | |
it isn't too many. | |
7) Fire up 1password and choose File>Import. You want to import keychain.csv as a "CSV or Delimited Text" | |
file. The process is fairly self-explanatory, make sure you select "comma" as the delimiter at the | |
appropriate point. You will have to tell it which columns correspond to which fields (this is pretty | |
obvious) and you should check that there are exactly five columns. If you're seeing more than five | |
columns, one of your values contains a rogue comma and you need to fix it manually before you import the | |
file or it won't work. The 5th column is optional - it's the last modified date for the keychain entry; | |
unfortunately 1password won't let you import this as the "modified date" for the password but I put | |
it in a notes field just in case since I often find it helpful to know when a password was set. | |
8) IMPORTANT: You now have 2 files on your hard disk that contain unencrypted passwords. You need to delete | |
these securely if you are concerned about the possibility that someone might get your passwords. You have | |
two options. The easy option is to use Finder to move them to Trash, and then Secure Empty Trash. If you | |
are one of these funny people who likes to use their Trash Can as a temporary storage location and don't | |
want to empty it, you can go back to the terminal and issue rm keychain.csv keychain.txt, and then fire up Disk | |
Utility and use the "Erase Free Space" command on the relevant hard disk to securely blank all the free | |
space on your drive (this may take some time). NB: If you have an SSD drive in your computer there will be | |
no Secure Empty Trash (only plain Empty Trash) and there will be no "Erase Free Space" in Disk Utility. | |
This is because some SSDs delete things much more permanently than traditional hard disks by default, so | |
these commands are redundant. Simply emptying the trash/rm-ing the file from the terminal will suffice in | |
this case. | |
Acknowledgements: The original ruby script was written by Morgan Schweers of https://github.com/cyberfox. I've merely fixed bits that didn't work for me, and added the script to push the Allow button + this documentation. |
tell application "System Events" | |
repeat while exists (processes where name is "SecurityAgent") | |
tell process "SecurityAgent" | |
click button "Allow" of group 1 of window 1 | |
end tell | |
delay 0.2 | |
end repeat | |
end tell |
#!/usr/bin/env ruby | |
# | |
# Usage: | |
# security dump-keychain -d login.keychain > keychain_logins.txt | |
# # Lots of clicking 'Always Allow', or just 'Allow', until it's done... | |
# curl -O curl -O https://raw.github.com/gist/1224792/06fff24412311714ad6534ab700a7d603c0a56c9/keychain.rb | |
# chmod a+x ./keychain.rb | |
# ./keychain.rb keychain_logins.txt | sort > logins.csv | |
# | |
# Then import logins.csv in 1Password using the format: | |
# Title, URL/Location, Username, Password | |
# Remember to check 'Fields are quoted', and the Delimiter character of 'Comma'. | |
require 'date' | |
class KeychainEntry | |
attr_accessor :fields | |
def initialize(keychain) | |
last_key = nil | |
@fields = {} | |
data = nil | |
aggregate = nil | |
lines = keychain.split("\n") | |
lines.each do |line| | |
# Everything after the 'data:' statement is data. | |
if data != nil | |
data << line | |
elsif aggregate != nil | |
if line[0] == " " | |
keyvalue = line.split('=', 2).collect { |kv| kv.strip } | |
aggregate[keyvalue.first] = keyvalue.last | |
else | |
@fields[last_key] = aggregate | |
aggregate = nil | |
end | |
end | |
if aggregate == nil | |
parts = line.split(':').collect { |piece| piece.strip } | |
if parts.length > 1 | |
@fields[parts.first] = parts.last | |
else | |
last_key = parts.first | |
data = [] if parts.first == "data" | |
aggregate = {} | |
end | |
end | |
end | |
@fields["data"] = data.join(" ") if data | |
end | |
end | |
def q(string) | |
"\"#{string}\"" | |
end | |
def process_entry(entry_string) | |
entry = KeychainEntry.new(entry_string) | |
if entry.fields['class'] == '"inet"' && ['"form"', '"dflt"'].include?(entry.fields['attributes']['"atyp"<blob>']) | |
site = entry.fields['attributes']['"srvr"<blob>'].gsub!('"', '') | |
path = entry.fields['attributes']['"path"<blob>'].gsub!('"', '') | |
proto= entry.fields['attributes']['"ptcl"<uint32>'].gsub!('"', '') | |
proto.gsub!('htps', 'https'); | |
user = entry.fields['attributes']['"acct"<blob>'].gsub!('"', '') | |
#user = entry.fields['attributes']['0x00000007 <blob>'].gsub!('"', '') | |
date_string = entry.fields['attributes']['"mdat"<timedate>'].gsub(/0x[^ ]+[ ]+/, '').gsub!('"', '') | |
date = DateTime.parse(date_string) | |
pass = entry.fields['data'][1..-2] | |
path = '' if path == '<NULL>' | |
url = "#{proto}://#{site}#{path}" | |
puts "#{site},#{url},#{user},#{pass},#{date}" | |
#puts "#{user}, #{pass}, #{date}" | |
end | |
end | |
accum = '' | |
ARGF.each_line do |line| | |
if line =~ /^keychain: / | |
unless accum.empty? | |
process_entry(accum) | |
accum = '' | |
end | |
end | |
accum += line | |
end |
Thanks, worked like a charm, I only had to change the delay in applescript from 0.2 to 0.4.
See https://gist.github.com/4247303 for two improvements:
- Use the standard Ruby CSV library to properly escape all values (comma or no comma).
- Add a quick error handling fix to the AppleScript so it recovers from failures more often.
I have to say... the "Allow button" script part is awesome and is the coolest thing i experienced lately ! thanks !
This looks good, but what I want to do is extract just my Secure Notes from KeyChain. I have searched everywhere and this is the most promising.
But I am lost in the script.
I realise that Secure Notes are generic password items "genp" and that I need to get "svce" into the script, but I need some help with this.
I was able to get it running under Mavericks with this version https://gist.github.com/1583781 and changing the ruby version in the command line. You can switch it back to 2.0 after.
$ PATH=/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin
@abrahamVelazquez i tried using the 1.8.7 ruby on os x 10.9 (and 2.0.0 before that) and i am still getting an empty csv file. any ideas?
See edit to line 30 at https://gist.github.com/1583781 to help it work with ruby 1.8 (default on Lion)