Last night when I couldn’t fall asleep all kinds of weird ideas kept flowing through my head. One of them was to write an AppleScript that could crack a password. So… having nothing better to do, I just wrote one. I’m not an expert scripter so there’s probably a lot that could be done cleaner and more efficient. If you want to chime in, you’re most welcome.
I considered compiling a list of wrong guesses to avoid repeating the same guess more than once, but it seemed to slow the process down considerably so I dropped it.
Judging from Activity Monitor, the script uses only one core on my dual core iMac. Is there any way to make it use both?
The variable appRate calculates the approximate rate (guesses per second) that can be expected. The equation I use to calculate this is one I got from Excel after having plotted several datapoints in a scatter chart and add a trendline. So the estimated number of guesses per second is based on my computer’s performance. However, if the script guesses your password, it will output the actual number of guesses it made.
set myPassword to text returned of (display dialog "Enter a password to guess" default answer "")
set passLength to count characters of myPassword
considering case
set lowerCase to "abcdefghijklmnopqrstuvwxyz"
set upperCase to "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
set theNumbers to "1234567890"
set theSymbols to "$§!\"#€%&/()=?`¡"§£âˆžâ„¢¶[]≠±'°âˆ‘é® ¥Ã¼|Å“Ï€˜~ªÃŸâˆ‚Æ’©«¹âˆ†¬Ã¤Ã¶@Ω.ç√∫ñµ<>≤≥,.-;:_žÃ·”"
set lowerCaseUsed to false
set upperCaseUsed to false
set theNumbersUsed to false
set theSymbolsUsed to false
repeat with i from 1 to passLength
if character i of myPassword is in lowerCase then
set lowerCaseUsed to true
else if character i of myPassword is in upperCase then
set upperCaseUsed to true
else if character i of myPassword is in theNumbers then
set theNumbersUsed to true
else if character i of myPassword is in theSymbols then
set theSymbolsUsed to true
end if
end repeat
set usedCharacters to ""
if lowerCaseUsed then set usedCharacters to usedCharacters & lowerCase
if upperCaseUsed then set usedCharacters to usedCharacters & upperCase
if theNumbersUsed then set usedCharacters to usedCharacters & theNumbers
if theSymbolsUsed then set usedCharacters to usedCharacters & theSymbols
try
set noPossibilities to ((count usedCharacters) ^ passLength) as integer
on error
set noPossibilities to ((count usedCharacters) ^ passLength)
end try
try
set appRate to 61448 * (noPossibilities ^ -0.054) as integer
on error
set appRate to 61448 * (noPossibilities ^ -0.054)
end try
display dialog "There are " & noPossibilities & " possibilities." & return & "At app. " & appRate & " guesses per second this will take" & return & convertTime((noPossibilities / appRate)) & " to guess." buttons {"Cancel", "Go ahead!"} default button "Cancel"
set correct to false
set wrongGuesses to 0
set timeStart to (current date)
repeat until correct
set theGuess to ""
set theGuess to some character of usedCharacters
repeat (passLength - 1) times
set theGuess to theGuess & some character of usedCharacters
end repeat
if theGuess is not myPassword then
set wrongGuesses to wrongGuesses + 1
else
set correct to true
end if
end repeat
end considering
set timeStop to (current date)
set timeTaken to (timeStop - timeStart)
if timeTaken < 1 then set timeTaken to 1
return "Your password is " & theGuess & ". It took " & timeTaken & " seconds and " & wrongGuesses & " guesses @ " & ((wrongGuesses / timeTaken) as integer) & " guesses per second." & return & return & "There were " & noPossibilities & " possibilities."
on convertTime(input)
if input is less than minutes then
set output to ((input as integer) as string) & " seconds"
else if input is less than hours then
set myMins to input div minutes
set mySecs to input mod minutes
set output to (myMins as string) & " minutes and " & (mySecs as integer) & " seconds"
else if input is less than days then
set myHours to input div hours
set myMins to input mod hours div minutes
set output to (myHours as string) & " hours and " & myMins & " minutes"
else if input is less than ((days * 365) / 12) then
set myDays to input div days
set myHours to input mod days div hours
set output to (myDays as string) & " days and " & myHours & " hours"
else if input is less than (days * 365) then
set myMonths to input div ((days * 365) / 12)
set myDays to input mod ((days * 365) / 12) div days
set output to (myMonths as string) & " months and " & myDays & " days"
else if input ≥ (days * 365) then
set myYears to input div (days * 365)
set myMonths to input mod (days * 365) div ((days * 365) / 12)
set output to (myYears as string) & " years and " & myMonths & " months"
end if
return output
end convertTime