When a user persists an encrypted disk (or disk image) passphrase in the Keychain (e.g via Disk Utility as shown here, https://apple.stackexchange.com/a/229309/5392 or when setting up an encrypted Time Machine backup, possibly on a remote device), an entry gets created in either the login (via Disk Utility) or System (for Time Machine) keychains.
Examining such an entry with security
provides the following data:
$ security find-generic-password -D "disk image password" -l "A65D7474-F452-51CB-9BCC-3D594C918978.sparsebundle"
keychain: "/Library/Keychains/System.keychain"
version: 256
class: "genp"
attributes:
0x00000007 <blob>="A65D7474-F452-51CB-9BCC-3D594C918978.sparsebundle"
0x00000008 <blob>=<NULL>
"acct"<blob>="17F24503-E0E2-45B9-86EA-C79D857BA2AC"
"cdat"<timedate>=0x32303137303131303132333130335A00 "20170110123103Z\000"
"crtr"<uint32>=<NULL>
"cusi"<sint32>=<NULL>
"desc"<blob>="disk image password"
"gena"<blob>=<NULL>
"icmt"<blob>=<NULL>
"invi"<sint32>=<NULL>
"mdat"<timedate>=0x32303137303131303132333130335A00 "20170110123103Z\000"
"nega"<sint32>=<NULL>
"prot"<blob>=<NULL>
"scrp"<sint32>=<NULL>
"svce"<blob>="A65D7474-F452-51CB-9BCC-3D594C918978.sparsebundle"
"type"<uint32>=<NULL>
The account's GUID matches none of the users that can be found via:
dscl /Search -list /Users GeneratedUID
The ultimate goal is to non-interactively create the necessary entry in the Keychain for Time Machine to pick up the password and attach an encrypted, size-limited sparsebundle disk image on a Time Capsule, for which this is the missing piece.
Unfortunately diskimages-helper
is not allowed to mount it (observed via Console.app
) when using the following command to create the entry:
sudo security add-generic-password -a "$username" -w "${passphrase}" -D "disk image password" -s "${sparsebundle}" -T /System/Library/PrivateFrameworks/DiskImages.framework/Versions/A/Resources/diskimages-helper /Library/Keychains/System.keychain
BTW this is on Sierra.
Additional references:
- https://sliwinski.com/mac-osx-lion-secure-backup-to-time-capsule-wi/
- How do I tell if a disk image (.sparseimage) is encrypted?
- https://techanic.net/2012/10/14/programmatically_mounting_encrypted_disk_images_in_os_x.html
- http://www.practiceofcode.com/post/749686705/encrypted-rotating-time-machine-backups-on-snow
- http://hints.macworld.com/article.php?story=20080519051720677
Best Answer
Getting the UUID:
The account field in the keychain entry corresponds to the UUID of the encrypted disk image which can be retrieved like this:
hdiutil isencrypted example.sparsebundle 2>&1 | grep uuid | cut -f2 -d" "
Note that the
hdiutil isencrypted
command always prints its output to stderr for some reason which is why we must redirect stderr to stdout (2>&1) before piping it to grep. Alternately, you can use the-plist
option and parse the XML if it fits your use case better.Creating the Keychain item:
For Time Machine to automatically do scheduled backups to a Time Capsule, the disk image password must be stored in the system wide keychain located at
/Library/Keychains/System.keychain
rather than your password protected user login keychain.To non-interactively create an entry in the System keychain, you can do:
we invoke the uuid command from the previous step in a subshell here to use as the account name.
Security Concerns:
Instead of a password, the System keychain is secured using a key file at
/private/var/db/SystemKey
. When the system is running, all admin users have permission to access the keychain.This isn't a security risk per se, but people often forget/overlook when enabling Time Machine that it's for the whole computer and not just their user account. Keep this in mind when choosing your Time Machine password not to use one that's very personal or private to you if you share adminship (and, obviously, make sure you've enabled FileVault full disk encryption to prevent 3rd party access).
Another concern is that while including your password inline as an argument with
-w
avoids the interactive password prompt, it is also insecure as it will be saved in plaintext to your shell history (if you don't supress it) and in the output of commands likeps
. And because you must specify the System keychain path as the last argument, it is very tricky to non-interactively add an item to the system keychain without exposing the password in this way.But there is an alternate, albeit more involved solution for adding items to the user login keychain that avoids exposing your password:
Using
expect
to handle interactive password prompts:Since you can't pipe the password to
security
directly, you can instead specify-w
as the last option and omit the password. This will make it prompt for a password, and then you can useexpect
to handle the interactive prompts programmatically - the caveat being you cannot specify which keychain to add the item to, so it will be added to the default login keychain.I'm not sure if this is within the scope of your question, but just in case, here's a quick and dirty
expect
script that allows you to non-interactively provide a password to the prompt:For example on how to run it, here I save it to a file
hdiutilAddToKeychain.exp
and pipe it a password from an imaginary function that you can substitute for however you get the password in your workflow:$ getPassword | ./hdiutilAddToKeychain.exp /path/to/example.sparsebundle
This should create the appropriate item in your login keychain, but the OS may still give you a GUI password prompt to allow access the first time you try to open it. I'm not aware of any way around this first time prompt.
You may also be able to use security's
export
andimport
subcommands to copy the password from your login keychain to the System keychain once it's been added this way.