Descramble Passwords from gftp Bookmarks using Python
If you check the file where gftp keeps its bookmarks, you will notice that passwords are not stored in clear text. Instead, gftp has used an algorithm to scramble them. I cannot recall if it was one or two years ago when I had decided to write a script to convert the bookmarks from the gftp format to the FileZilla format, but I do recall that I had to descramble the passwords from the gftp bookmarks and the C code of that password descrambling algorithm had given me a hard time, because I had to port it to Python, since Python was the programming language I intended to use for my bookmark converter. At that time, I happened to hang out at #python, so I had asked for some help there and a kind fellow pythonista had saved the day.
The original password descrambling algorithm in C as found in the gftp sources at that time (gftp-2.0.18/lib/misc.c):
char * gftp_descramble_password (const char *password) { const char *passwordpos; char *newstr, *newpos; int error; if (*password != '$') return (g_strdup (password)); passwordpos = password + 1; newstr = g_malloc (strlen (passwordpos) / 2 + 1); newpos = newstr; error = 0; while (*passwordpos != '\0' && (*passwordpos + 1) != '\0') { if ((*passwordpos & 0xc3) != 0x41 || (*(passwordpos + 1) & 0xc3) != 0x41) { error = 1; break; } *newpos++ = ((*passwordpos & 0x3c) << 2) | ((*(passwordpos + 1) & 0x3c) >> 2); passwordpos += 2; } if (error) { g_free (newstr); return (g_strdup (password)); } *newpos = '\0'; return (newstr); }
The following is the Python port of the above code. The person who did the porting wished to remain nameless. The exact answer I got when I had asked about how I should give him credit for the code was:
please don’t attach my name to it. it’s horrible, awful code. Consider it public domain, do with it as you wish.
Python port:
def gftp_descrable_password(password): """gftp password descrambler This code has been released in the Public Domain by the original author. """ if not password.startswith('$'): return password newpassword = [] pwdparts = map(ord, password) for i in range(1, len(pwdparts), 2): if ((pwdparts[i] & 0xc3) != 0x41 or (pwdparts[i+1] & 0xc3) != 0x41): return password newpassword.append(chr(((pwdparts[i] & 0x3c) << 2) + ((pwdparts[i+1] & 0x3c) >> 2))) return "".join(newpassword)
The only thing I have added to the above code is the docstring so that the function can be reused without licensing issues.
The above snippet has not been thoroughly tested, but it seems to work fine.
As for the bookmark converter, I am not interested in doing it any more.
