5
\$\begingroup\$

Oplop is an algorithm to generate website specific passwords based on a master password and a keyword.

It is described here: http://code.google.com/p/oplop/wiki/HowItWorks

There's an online implementation here: https://oplop.appspot.com/

My attempt in Q is 204 200 167 165 139 characters ignoring whitespace:

{d:.Q.A,.Q.a,(n:"0123456789"),"-_";
b:d 2 sv'6 cut(,/)0b vs'(md5 x,y),2#0x00;
i:b in n;j:i?1b;k:(j _i)?0b;
8#$[0=0+/i;"1";8>j;();b j+(!)k],b}

EDIT: I achieved significant character savings by removing some redundant code from my Hex->Base64 conversion.

2012.03.07 - Cut out 2 more characters

2012.03.11 - Removed duplication and got accurate char count

2012.03.20 - Down to 141

Criteria

Candidate functions/implementations should take two strings as arguments and return an 8 character password as defined in the algorithm.

Judging

Code golf so shortest code takes the prize.

\$\endgroup\$
3
  • \$\begingroup\$ When will the judging be done? \$\endgroup\$ Commented Mar 21, 2012 at 12:22
  • \$\begingroup\$ I'll give it until the end of the month. 2012-04-01 00:00:00.000 \$\endgroup\$
    – skeevey
    Commented Mar 21, 2012 at 13:16
  • 1
    \$\begingroup\$ Imho, the problem description should be complete in that way, that an average programmer knows what to do. So you should name the steps to generate the code, while it is to the user to find out how to md5sum or to base64encode something. A website for further details is welcome, of course. Preparing a challenge on meta or in chat is - btw. - recommended. \$\endgroup\$ Commented Mar 28, 2012 at 20:46

4 Answers 4

5
\$\begingroup\$

Python - 198 166 152 150

import base64,md5,sys,re
b=base64.urlsafe_b64encode(md5.md5(sys.argv[1]+sys.argv[2]).digest())
r=re.findall('\d+',b)if all(not c.isdigit()for c in b[:8])else['']
print((r[0]if len(r)else'1')+b)[:8]

import base64,md5,sys,re
b=base64.urlsafe_b64encode(md5.md5("".join(sys.argv[1:])).digest())
print((''if re.search('\d',b[:8])else re.findall('\d+',b+'1')[0])+b)[:8]

import base64,md5,sys,re
b=base64.urlsafe_b64encode(md5.md5("".join(sys.argv[1:])).digest())
print(re.findall('(?:[^\d]{8,}(\d*)|)',b+' 1')[0]+b)[:8]

This was a fun one. Could be a lot shorter if not for the verbosity of the md5 and base64 modules. The third and fourth lines are the interesting ones. My favourite trick was using a list containing only an empty string to avoid having to use any real if statements.

EDIT: Had to change from checking c.isalpha() to not c.isdigit() (added 4 characters)

EDIT: Shaved off 32 characters. Many thanks to Ugoren!

EDIT: Shaved off 14 more chars again many thanks to Ugoren. Used some regex trickiness

print(re.findall('(?:[^\d]{8,}(\d*)|)',b+' 1')[0]+b)[:8]

instead of

print((re.findall('^[^\d]{8,}(\d*)',b+' 1')+[''])[0]+b)[:8]

To save three chars.

\$\endgroup\$
9
  • \$\begingroup\$ This seems to give incorrect values for some input eg. (a,aaaa) \$\endgroup\$
    – skeevey
    Commented Feb 28, 2012 at 2:09
  • \$\begingroup\$ Oh shoot, I know why. I'll update in a second, thanks for catching that. \$\endgroup\$ Commented Feb 28, 2012 at 2:11
  • \$\begingroup\$ Small improvements: "".join(sys.argv[1:3]) (or even [1:]), if r can replace if len(r) (I think), re.match('^[^\d]{8}',b). \$\endgroup\$
    – ugoren
    Commented Feb 28, 2012 at 13:46
  • \$\begingroup\$ Also - r=re.findall('\d+',b+' 1') allows you to remove the if-else later (and then you don't need r). And reversing if-else on line 3 allows using re.match('\d',b[:8]) instead of my above suggestion. \$\endgroup\$
    – ugoren
    Commented Feb 28, 2012 at 14:16
  • \$\begingroup\$ Nice tips, shaved off 32 characters, thanks! \$\endgroup\$ Commented Feb 28, 2012 at 15:44
5
\$\begingroup\$

Shell - 116

echo -n $1$2|md5sum|xxd -r -p|base64|sed -re'y!+/!-_!;/^.{0,7}[0-9]/!{s/^([^0-9]*)([0-9]+)/\2\1/;t;s/^/1/}'|cut -c-8

Depends on cut, md5sum and base64 from coreutils, xxd and GNU sed.

\$\endgroup\$
3
\$\begingroup\$

Ruby (113 110 chars)

require 'digest'
b=Digest::MD5.base64digest(ARGV.join)
puts "#{b} 1".sub(/(^\D{8,}(\d*))/,'\2\1')[0..7].tr'+/','-_'

require'digest'
b=Digest::MD5.base64digest(ARGV.join)
puts"#{b} 1".sub(/(^\D{8,}(\d*))/,'\2\1')[0,8].tr'+/','-_'

I notice that all the non-Python languages have to do a translation of the + and / to be - and _, respectively. It seems that Python's base64 is different/wrong?

\$\endgroup\$
1
  • 2
    \$\begingroup\$ There are several variants for different applications where different characters need escaping. Note that the Python method used is called urlsafe_b64encode \$\endgroup\$ Commented Mar 8, 2012 at 11:10
2
\$\begingroup\$

PHP (126)

function f($m,$n){return substr(preg_replace('/^\D{8,}(\d+)/','$1$0',strtr(base64_encode(md5($m.$n,1)),'+/','-_').' 1'),0,8);}

Beautified:

function oplop( $master, $nick ) {
    return substr( preg_replace(
        '/^\D{8,}(\d+)/', '$1$0',
        strtr( base64_encode( md5( $master . $nick, true ) ), '+/', '-_' ) . ' 1'
    ), 0, 8 );
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.