Accessing files on an encrypted .DMG

Here’s what I’m trying to do -

I have created an encrypted .DMG called ‘Test.dmg’ with a password of ‘password’ and have several SQLite3 databases and some admin level scripts in it. What I want to do is access the files on the .DMG but NOT mount it. I want to be able to write a script (or an XCode interface) which, when it needs to access the data in the databases or run the functions of the admin scripts, will access the .DMG with the password but not save it in the system keychain or mount it so users can access the data manually. I know I can mount it but that, in my mind, defeats the reason I bothered to encrypt and password protect it.

Is something like this possible?

All I have so far is:

property pDongleMounted : false -- Default value
property pDongleName : "Test" -- The name of the .dmg file

set lReply to "USB Dongle not found."
set lParseUSBPorts to (do shell script "system_profiler SPUSBDataType") as text

if lParseUSBPorts contains "0x1607" and lParseUSBPorts contains "0x0951" and lParseUSBPorts contains "001000000000000000000279" then
	set lReply to my sMountDongle(pDongleName)
end if

return lReply

--> Mount Dongle image (How do I do this when the .dmg requires a password?)

on sMountDongle(pDongleName)
	set lDongleImagePath to "USB_Dongle:" & pDongleName & ".dmg"
	do shell script "hdiutil attach " & quoted form of POSIX path of lDongleImagePath
	return "Image mounted."
end sMountDongle

--> Unmount Dongle image (Do this AFTER data is accessed)

on sUnMountDongle(pDongleName)
	tell application "System Events"
		set lDongleImage to (pDongleName is in (get name of disks))
		if lDongleImage then set pDongleMounted to true
	end tell
	
	if pDongleMounted then do shell script "hdiutil unmount " & quoted form of ("/Volumes/" & pDongleName)
	return "Image unmounted."
end sUnMountDongle

which does not even address opening the image using a password , and if you can access the data without mounting the image, can you at least make it invisible?

Have you looked at the -nobrowse option when doing your attach?

hdiutil attach /path/to/dmg -nobrowse

Actually I got that shell script from other examples on this site so no. I didn’t know that WAS an option, so thanks!

Okay, this works like a charm but I was wondering - While I don’t SEE it mounted on the desktop I can see it is mounted when I open Disk Utility. Does that mean that a user could if they so choose access the contents of the mounted image as long as it remains open or does the -nobrowse option make it inaccessible? By the way, is there a option like -withpassword “password” so you can open a password protected image?

property pDMGMounted : false -- Default value
property pDMGName : "Test" -- The name of the .dmg file

set lReply to "USB Dongle not found."
set lParseUSBPorts to (do shell script "system_profiler SPUSBDataType") as text

if lParseUSBPorts contains "0x1607" and lParseUSBPorts contains "0x0951" and lParseUSBPorts contains "001000000000000000000279" then
	set lReply to my sMountDMG(pDMGName)
end if

return lReply

--> Mount Dongle image

on sMountDMG(pDMGName)
	set lDMGImage to "USB_Dongle:" & pDMGName & ".dmg"
	do shell script ("hdiutil attach " & (quoted form of POSIX path of lDMGImage) & " -nobrowse")
	return "Image mounted."
end sMountDMG

--> Unmount Dongle image (Do this AFTER data is accessed)

on sUnMountDMG(pDMGName)
	tell application "System Events"
		set lDMGImage to (pDMGName is in (get name of disks))
		if lDMGImage then set pDMGMounted to true
	end tell
	
	if pDMGMounted then do shell script "hdiutil unmount " & quoted form of ("/Volumes/" & pDMGName)
	return "Image unmounted."
end sUnMountDMG

Well in terms of the password you would go like this

echo -n password|hdiutil attach ~/Desktop/Test.dmg -stdinpass

As for making it completely unaccessible to the end user I don’t think you can. You can add the nobrowse as I said which hides it, but you can’t really make invisible/locked. The only thing I can think of would maybe be to try doing the following…

Set the owners of the files on the DMG to root and give it permissions of execute only. Then incase they have ignore permissions set you could attach the dmg with the ‘-owners on’ option.

The only problem with all of this is if they have a admin account on the machine anything you do they can pretty much work around.

Well, I tried to shoehorn what you gave me into my script but I am getting the error:

From your suggestion of:

echo -n password|hdiutil attach ~/Desktop/Test.dmg -stdinpass

I wrote:

do shell script ("echo -n " & pDMGPwd & "|hdiutil attach " & (quoted form of POSIX path of lDMGImage) & " -stdinpass -nobrowse")

which translates into do shell script (“echo -n password|hdiutil attach /Volumes/USB_Dongle/Test.dmg -stdinpass -nobrowse”)

To me it looks like the only thing my code was missing was the tilde in from the front of the path, so I added it but now get the error:

What have I done wrong? The full script is below… By the way, I like your ideas regarding the setting of the file owners to root and execute only. I think I will make two versions, give them both a spin, and determine from there which one will be the best fit.

property pDMGMounted : false -- Default value
property pDMGName : "Test" -- The name of the .dmg file
property pDMGPwd : "password" -- The password for the .dmg file

set lParseUSBPorts to (do shell script "system_profiler SPUSBDataType") as text
set lReply to "Default reply." -- Only necessary while testing

if lParseUSBPorts contains "0x1607" and lParseUSBPorts contains "0x0951" and lParseUSBPorts contains "001000000000000000000279" then
	my sMountDMG(pDMGName)
	-- Do everything with files on the password protected image here
	set lReply to my sUnMountDMG(pDMGName)
	
else
	set lReply to "USB Dongle not found."
end if

return lReply

--> Mount Dongle image

on sMountDMG(pDMGName)
	set lDMGImage to "USB_Dongle:" & pDMGName & ".dmg"
	do shell script ("echo -n " & pDMGPwd & "|hdiutil attach " & (quoted form of POSIX path of lDMGImage) & " -stdinpass -nobrowse")
end sMountDMG

--> Unmount Dongle image (Do this AFTER data is accessed)

on sUnMountDMG(pDMGName)
	tell application "System Events"
		set lDMGImage to (pDMGName is in (get name of disks))
		if lDMGImage then set pDMGMounted to true
	end tell
	
	if pDMGMounted then do shell script "hdiutil unmount " & quoted form of ("/Volumes/" & pDMGName)
	return "Image unmounted." -- Only necessary while testing
end sUnMountDMG

You want to keep the ~ out (at least in the way you are referring to the file right now), but give this a try

Try swapping the location of the stdinpass option with nobrowse.

I can’t test at the moment, but thats the only thing I can think of because your syntax appears correct,

Also results in hdiutil: attach failed - Authentication error.

HOLD THE PHONE! I just save the script as an application and ran it just for grins, and as an application it DOES mount the .dmg image. What’s with that? As a script it fails - as an application it works… :confused:

and removing -nobrowse completely for testing purposes?

with -nobrowse removed it mounts the image if run as a script (didn’t try it as an application but assume it works as an app).

I think I MAY have figured out where my mistake was (actually I know WHERE it was , I guess WHY it was occurring is more accurate).

Here is where the problem was:

if lParseUSBPorts contains "0x1607" and lParseUSBPorts contains "0x0951" and lParseUSBPorts contains "001000000000000000000279" then
	my sMountDMG(pDMGName)

When I change my sMountDMG(pDMGName) to either set x to my sMountDMG(pDMGName) OR I follow it with delay 2 the problem goes away. I guess it was trying to unmount the image before or while it was in the process of being mounted and setting the result as a variable or adding a bit of delay to the script gives it time to finish up.

On my machine it works as script with the full paths of the binaries


.
do shell script ("/bin/echo -n " & quoted form of the pDMGPwd & " | /usr/bin/hdiutil attach -stdinpass " & quoted form of POSIX path of lDMGImage)
.

Thanks to James and Stefan the following is the script, pared down slightly. This is by no mean the whole project but since this works I will be putting it the time to design a functional application that incorporates a dongle and then test the security of it. If it works and is useful I will post the code and instructions. No promises when I will be done with this though:D

property pDMGName : "Test" -- The name of the .dmg file
property pDMGPwd : "password" -- The password for the .dmg file

set lParseUSBPorts to (do shell script "system_profiler SPUSBDataType") as text

if lParseUSBPorts contains "0x1607" and lParseUSBPorts contains "0x0951" and lParseUSBPorts contains "001000000000000000000279" then
	set lReply to my sMountDMG(pDMGName)
	set lDMGImagePath to ("Volumes:" & pDMGName)
	
	(* ALL FILE ACTIONS GO BELOW THIS !!! *)

	(* ALL FILE ACTIONS GO ABOVE THIS !!! *)
	
	tell application "System Events" to set lDMGImage to (pDMGName is in (get name of disks))
	set lReply to my sUnMountDMG(pDMGName, lDMGImage, lDMGImagePath)
	--set lReply to sEjectDMG(pDMGName, lDMGImage, lDMGImagePath)
end if

--> Mount Dongle image

on sMountDMG(pDMGName)
	set lDMGImage to ("USB_Dongle:" & pDMGName & ".dmg") as text
	do shell script ("/bin/echo -n " & quoted form of the pDMGPwd & " | /usr/bin/hdiutil attach -stdinpass " & quoted form of POSIX path of lDMGImage & " -nobrowse")
end sMountDMG

--> Unmount Dongle image (Do this AFTER data is accessed)

on sUnMountDMG(pDMGName, lDMGImage, lDMGImagePath)
	if lDMGImage then do shell script ("/usr/bin/hdiutil unmount " & quoted form of POSIX path of lDMGImagePath)
end sUnMountDMG

--> Eject Dongle image

on sEjectDMG(pDMGName, lDMGImage, lDMGImagePath)
	if lDMGImage then do shell script ("/usr/bin/hdiutil detach " & quoted form of POSIX path of lDMGImagePath)
end sEjectDMG

I tried your solution, changing only what was relevant to my use, as it was closest to what I want to do. I want to make a dmg that behaves like an Installer. To that end I want to open an encrypted dmg using Applescript (if the User agrees to the Licese Agreement) then run some other suff.

I have all files; Test.dmg Test.scpt Test.app together on the Desktop. But I get: Applescript Error - hdiutil: attach failed - No such file or directory

Did you ever get this working correctly?


property pDMGName : "Test" -- The name of the .dmg file
property pDMGPwd : "Password" -- The password for the .dmg file

--> Confirm
set dialog to display dialog "Mount, Unencrypt, Expand 'Test.dmg' ?

" buttons {"Cancel", "OK"} cancel button 1
set pressed to button returned of dialog

if pressed is equal to "OK" then
	set lReply to my sMountDMG(pDMGName)
	set lDMGImagePath to ("Volumes:" & pDMGName)
	
	(* ALL FILE ACTIONS GO BELOW THIS !!! *)
	
	(* ALL FILE ACTIONS GO ABOVE THIS !!! *)
	
	tell application "System Events" to set lDMGImage to (pDMGName is in (get name of disks))
	set lReply to my sUnMountDMG(pDMGName, lDMGImage, lDMGImagePath)
	--set lReply to sEjectDMG(pDMGName, lDMGImage, lDMGImagePath)
end if

--> Mount Dongle image

on sMountDMG(pDMGName)
	set lDMGImage to (pDMGName & ".dmg") as text
	do shell script ("/bin/echo -n " & quoted form of the pDMGPwd & " | /usr/bin/hdiutil attach -stdinpass " & quoted form of POSIX path of lDMGImage & " -nobrowse")
end sMountDMG

--> Unmount Dongle image (Do this AFTER data is accessed)

on sUnMountDMG(pDMGName, lDMGImage, lDMGImagePath)
	if lDMGImage then do shell script ("/usr/bin/hdiutil unmount " & quoted form of POSIX path of lDMGImagePath)
end sUnMountDMG

--> Eject Dongle image

on sEjectDMG(pDMGName, lDMGImage, lDMGImagePath)
	if lDMGImage then do shell script ("/usr/bin/hdiutil detach " & quoted form of POSIX path of lDMGImagePath)
end sEjectDMG