Dienstag, 12. April 2011

JavaSCrypt - A crypt(3) implementation in JavaScript

For my Password Generator which I plan to port to JavaScript, I need to have an implementation of crypt(3) for JavaScript.

I quickly found, a source code online, buthad some problems porting it.

Searching the web a bit more I found Michael Dipperstein's page describing a bug, or better, implementation detail which hit him. Applying his changes, I got my JavaScript version running.

So here is the - straightforward - implementation of crypt(3) in JavaScript.



<html>
<head>
<script>
/*
* This program implements the
* Proposed Federal Information Processing
* Data Encryption Standard.
* See Federal Register, March 17, 1975 (40FR12134)
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* The source is taken from
* http://google.com/codesearch/p#ZWtxA-fyzBo/UnixArchive/PDP-11/Distributions/research/Henry_Spencer_v7/v7.tar.gz%7C118goTAkg2o/usr/src/libc/gen/crypt.c
* and bug-fixed according to
* http://michael.dipperstein.com/crypt/crypt3.c
*
* permission is granted to use this code at your own will nad risk
* I don't guarantee anything.
*
* Written 2011-04-12 by Skeeve
* mail: javascrypt.v0-1.skeeve et xoxy dot net
*/

function JavaSCrypt() {

/*
* Initial permutation,
*/
const IP = [
58,50,42,34,26,18,10, 2,
60,52,44,36,28,20,12, 4,
62,54,46,38,30,22,14, 6,
64,56,48,40,32,24,16, 8,
57,49,41,33,25,17, 9, 1,
59,51,43,35,27,19,11, 3,
61,53,45,37,29,21,13, 5,
63,55,47,39,31,23,15, 7,
];

/*
* Final permutation, FP = IP^(-1)
*/
const FP = [
40, 8,48,16,56,24,64,32,
39, 7,47,15,55,23,63,31,
38, 6,46,14,54,22,62,30,
37, 5,45,13,53,21,61,29,
36, 4,44,12,52,20,60,28,
35, 3,43,11,51,19,59,27,
34, 2,42,10,50,18,58,26,
33, 1,41, 9,49,17,57,25,
];

/*
* Permuted-choice 1 from the key bits
* to yield C and D.
* Note that bits 8,16... are left out:
* They are intended for a parity check.
*/
const PC1_C = [
57,49,41,33,25,17, 9,
1,58,50,42,34,26,18,
10, 2,59,51,43,35,27,
19,11, 3,60,52,44,36,
];

const PC1_D = [
63,55,47,39,31,23,15,
7,62,54,46,38,30,22,
14, 6,61,53,45,37,29,
21,13, 5,28,20,12, 4,
];

/*
* Sequence of shifts used for the key schedule.
*/
const shifts = [
1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1,
];

/*
* Permuted-choice 2, to pick out the bits from
* the CD array that generate the key schedule.
*/
const PC2_C = [
14,17,11,24, 1, 5,
3,28,15, 6,21,10,
23,19,12, 4,26, 8,
16, 7,27,20,13, 2,
];

const PC2_D = [
41,52,31,37,47,55,
30,40,51,45,33,48,
44,49,39,56,34,53,
46,42,50,36,29,32,
];

/*
* The C and D arrays used to calculate the key schedule.
*/

var C=new Array(28);
var D=new Array(28);
/*
* The key schedule.
* Generated from the key.
*/
var KS=new Array(
new Array(48),new Array(48),new Array(48),new Array(48),
new Array(48),new Array(48),new Array(48),new Array(48),
new Array(48),new Array(48),new Array(48),new Array(48),
new Array(48),new Array(48),new Array(48),new Array(48),
new Array(48),new Array(48),new Array(48),new Array(48)
);
/*
* Set up the key schedule from the key.
*/
function setkey(key) {
/*
* First, generate C and D by permuting
* the key. The low order bit of each
* 8-bit char is not used, so C and D are only 28
* bits apiece.
*/
for (var i=0; i<28; i++) {
C[i] = key[PC1_C[i]-1];
D[i] = key[PC1_D[i]-1];
}
/*
* To generate Ki, rotate C and D according
* to schedule and pick up a permutation
* using PC2.
*/
for (var i=0; i<16; i++) {
/*
* rotate.
*/
for (var k=0; k<shifts[i]; k++) {
var t = C[0];
for (var j=0; j<28-1; j++)
C[j] = C[j+1];
C[27] = t;
t = D[0];
for (j=0; j<28-1; j++)
D[j] = D[j+1];
D[27] = t;
}
/*
* get Ki. Note C and D are concatenated.
*/
for (var j=0; j<24; j++) {
KS[i][j] = C[PC2_C[j]-1];
KS[i][j+24] = D[PC2_D[j]-28-1];
}
}
}

/*
* The E bit-selection table.
*/
var E= new Array(48);
var e= [
32, 1, 2, 3, 4, 5,
4, 5, 6, 7, 8, 9,
8, 9,10,11,12,13,
12,13,14,15,16,17,
16,17,18,19,20,21,
20,21,22,23,24,25,
24,25,26,27,28,29,
28,29,30,31,32, 1,
];

/*
* The 8 selection functions.
* For some reason, they give a 0-origin
* index, unlike everything else.
*/
const S= [
[
14, 4,13, 1, 2,15,11, 8, 3,10, 6,12, 5, 9, 0, 7,
0,15, 7, 4,14, 2,13, 1,10, 6,12,11, 9, 5, 3, 8,
4, 1,14, 8,13, 6, 2,11,15,12, 9, 7, 3,10, 5, 0,
15,12, 8, 2, 4, 9, 1, 7, 5,11, 3,14,10, 0, 6,13,
],
[
15, 1, 8,14, 6,11, 3, 4, 9, 7, 2,13,12, 0, 5,10,
3,13, 4, 7,15, 2, 8,14,12, 0, 1,10, 6, 9,11, 5,
0,14, 7,11,10, 4,13, 1, 5, 8,12, 6, 9, 3, 2,15,
13, 8,10, 1, 3,15, 4, 2,11, 6, 7,12, 0, 5,14, 9,
],
[
10, 0, 9,14, 6, 3,15, 5, 1,13,12, 7,11, 4, 2, 8,
13, 7, 0, 9, 3, 4, 6,10, 2, 8, 5,14,12,11,15, 1,
13, 6, 4, 9, 8,15, 3, 0,11, 1, 2,12, 5,10,14, 7,
1,10,13, 0, 6, 9, 8, 7, 4,15,14, 3,11, 5, 2,12,
],
[
7,13,14, 3, 0, 6, 9,10, 1, 2, 8, 5,11,12, 4,15,
13, 8,11, 5, 6,15, 0, 3, 4, 7, 2,12, 1,10,14, 9,
10, 6, 9, 0,12,11, 7,13,15, 1, 3,14, 5, 2, 8, 4,
3,15, 0, 6,10, 1,13, 8, 9, 4, 5,11,12, 7, 2,14,
],
[
2,12, 4, 1, 7,10,11, 6, 8, 5, 3,15,13, 0,14, 9,
14,11, 2,12, 4, 7,13, 1, 5, 0,15,10, 3, 9, 8, 6,
4, 2, 1,11,10,13, 7, 8,15, 9,12, 5, 6, 3, 0,14,
11, 8,12, 7, 1,14, 2,13, 6,15, 0, 9,10, 4, 5, 3,
],
[
12, 1,10,15, 9, 2, 6, 8, 0,13, 3, 4,14, 7, 5,11,
10,15, 4, 2, 7,12, 9, 5, 6, 1,13,14, 0,11, 3, 8,
9,14,15, 5, 2, 8,12, 3, 7, 0, 4,10, 1,13,11, 6,
4, 3, 2,12, 9, 5,15,10,11,14, 1, 7, 6, 0, 8,13,
],
[
4,11, 2,14,15, 0, 8,13, 3,12, 9, 7, 5,10, 6, 1,
13, 0,11, 7, 4, 9, 1,10,14, 3, 5,12, 2,15, 8, 6,
1, 4,11,13,12, 3, 7,14,10,15, 6, 8, 0, 5, 9, 2,
6,11,13, 8, 1, 4,10, 7, 9, 5, 0,15,14, 2, 3,12,
],
[
13, 2, 8, 4, 6,15,11, 1,10, 9, 3,14, 5, 0,12, 7,
1,15,13, 8,10, 3, 7, 4,12, 5, 6,11, 0,14, 9, 2,
7,11, 4, 1, 9,12,14, 2, 0, 6,10,13,15, 3, 5, 8,
2, 1,14, 7, 4,10, 8,13,15,12, 9, 0, 3, 5, 6,11,
],
];

/*
* P is a permutation on the selected combination
* of the current L and key.
*/
const P= [
16, 7,20,21,
29,12,28,17,
1,15,23,26,
5,18,31,10,
2, 8,24,14,
32,27, 3, 9,
19,13,30, 6,
22,11, 4,25,
];

/*
* The combination of the key and the input, before selection.
*/
var preS= new Array(48);

/*
* The payoff: encrypt a block.
*/

function encrypt(block, edflag) {
/*
* The current block, divided into 2 halves.
*/
var L= new Array(32);
var R= new Array(32);
var tempL= new Array(32);
var f= new Array(32);

/*
* First, permute the bits in the input
*/
for (var j=0; j<32; j++) {
L[j] = block[IP[j]-1];
R[j] = block[IP[j+32]-1];
}
/*
* Perform an encryption operation 16 times.
*/
for (var ii=0; ii<16; ii++) {
/*
* Set direction
*/
var i= (edflag>0) ? 15-ii : ii;
/*
* Save the R array,
* which will be the new L.
*/
for (var j=0; j<32; j++)
tempL[j] = R[j];
/*
* Expand R to 48 bits using the E selector;
* exclusive-or with the current key bits.
*/
for (var j=0; j<48; j++)
preS[j] = R[E[j]-1] ^ KS[i][j];
/*
* The pre-select bits are now considered
* in 8 groups of 6 bits each.
* The 8 selection functions map these
* 6-bit quantities into 4-bit quantities
* and the results permuted
* to make an f(R, K).
* The indexing into the selection functions
* is peculiar; it could be simplified by
* rewriting the tables.
*/
for (var j=0; j<8; j++) {
var t = 6*j;
var k = S[j][(preS[t+0]<<5)+
(preS[t+1]<<3)+
(preS[t+2]<<2)+
(preS[t+3]<<1)+
(preS[t+4]<<0)+
(preS[t+5]<<4)];
t = 4*j;
f[t+0] = (k>>3)&01;
f[t+1] = (k>>2)&01;
f[t+2] = (k>>1)&01;
f[t+3] = (k>>0)&01;
}
/*
* The new R is L ^ f(R, K).
* The f here has to be permuted first, though.
*/
for (var j=0; j<32; j++)
R[j] = L[j] ^ f[P[j]-1];
/*
* Finally, the new L (the original R)
* is copied back.
*/
for (var j=0; j<32; j++)
L[j] = tempL[j];
}
/*
* The output L and R are reversed.
*/
for (var j=0; j<32; j++) {
var t = L[j];
L[j] = R[j];
R[j] = t;
}
/*
* The final output
* gets the inverse permutation of the very original.
*/
for(var j = 0; j < 64; j++) {
var i = FP[j]-1;
if (i < 32)
block[j] = L[i];
else
block[j] = R[i - 32];
}
return block;
}

this.crypt= function (pw,salt) {
const charZ= "Z".charCodeAt(0);
const char9= "9".charCodeAt(0);
const charDot= ".".charCodeAt(0);
var i;
var j;
var c;
var temp;
var block= new Array(66);
var iobuf= new Array(16);
for(var i=0; i<66; i++)
block[i] = 0;
var ii;
for(i=0, ii=0; ii<pw.length && (c= pw.charCodeAt(ii)) && i<64; i++, ii++){
for(j=0; j<7; j++, i++)
block[i] = (c>>(6-j)) & 01;
}
setkey(block);

for(i=0; i<66; i++)
block[i] = 0;

for(i=0;i<48;i++)
E[i] = e[i];

for(i=0;i<2;i++){
c = salt.charCodeAt(i);
iobuf[i] = c;
if(c > charZ) c -= 6;
if(c > char9) c -= 7;
c -= charDot;
for(j=0;j<6;j++){
if(((c>>j) & 01) > 0){
temp = E[6*i+j];
E[6*i+j] = E[6*i+j+24];
E[6*i+j+24] = temp;
}
}
}

for(i=0; i<25; i++)
block= encrypt(block,0);

for(i=0; i<11; i++){
c = 0;
for(j=0; j<6; j++){
c <<= 1;
c |= block[6*i+j];
}
c += charDot;
if(c > char9) c += 7;
if(c > charZ) c += 6;
iobuf[i+2] = c;
}
iobuf[i+2] = 0;
if(iobuf[1]==0)
iobuf[1] = iobuf[0];
var result="";
for (i=0; iobuf[i]>0; ++i) {
result+= String.fromCharCode(iobuf[i]);
}
return(result);
}

}
var javascrypt= new JavaSCrypt;
</script>
</head>
<body>
<form action="javascript:false;">
Pass: <input type="text" name="pwd">
<br>
Salt: <input type="text" name="salt" maxlength="2">
<br/>
<button onclick="this.form.result.value=javascrypt.crypt(this.form.pwd.value, this.form.salt.value)">encrypt</button>
<br>
<input type="text" name="result" disabled="disabled">
</body>
</html>


Samstag, 9. April 2011

Passwort Generator

Ich brauchte mal wieder ein Passwort.

Und als ich mich in meinen Mailaccount einloggte und sah "118" fehlgeschlagene Login Versuche, habe ich mir gedacht, jetzt muß aber mal wirklich was sicheres her.

Da fiel mir ein Applescript ein, was ich vor Äonen mal in einem ehemals guten Appleforum veröffentlicht hatte. Zum Glück gibt es das Script dort noch und ich habe es mal rasch überarbeitet und erweitert.

Anmerkung: Dies ist eine erneut überarbeitete Version.
Anmerkung 2: Und nocheinmal überarbeitet. Außerdem plane ich eine JavaScript Version.

Die Vorteile des Scripts:
  1. Man kann ein simples Passwort eingeben.
  2. Man bekommt daraus immer dasselbe schwierige Passwort generiert.
  3. Dieses schwierige Passwort ist ziemlich sicher nicht zu erraten.
  4. Man kann den Generator immer wieder verwenden um sich sein schwieriges Passwort zu regenerieren. Deswegen braucht man es sich auch nirgends zu speichern.
  5. Es gibt einen "Copy" Knopf mit dem das generierte Passwort in das Clipboard kopiert werden kann um es so einfach per cmd-V zu übernehmen


--
-- Passwort Generator v0.4.2 von Skeeve
--
-- Dies AppleScript darf frei verwendet werden.
-- Es wird keinerlei Gewähr für irgendetwas übernommen.
-- Insbesondere nicht für die Sicherheit der generierten
-- Passworte!
--
-- Fragen und Anregungen bitte an
-- pwdgen.v0-4-2.skeeve et xoxy punkt net
--
on run
set version to "Passwort Generator v0.4.2"
set input to ""
repeat
set input to text returned of (display dialog "Gib Dein Passwort ein." & return & return & "Es wird dann eine sichere Variante generiert." default answer input with title version)
if input ≠ "" then exit repeat
end repeat
repeat
set input to do shell script "perl -e '
$s=substr($_=shift, 0, 2);
$s=substr(crypt($s,$s), -2);
print $s;
print substr crypt($1, $s),2 foreach (/(.{1,8})/g);
' " & quoted form of input
repeat
set choice to display dialog "Gib Dein Passwort ein, um ein weiteres sicheres zu generieren." & return & return & "• Dein sicheres Passwort lautet •" default answer input buttons {"OK", "Copy", "Cancel"} default button 1 with title version
set input to the text returned of choice
set choice to the button returned of choice
if choice is "Cancel" then return
if choice is "Copy" then
set the clipboard to the input
else
exit repeat
end if
end repeat
end repeat
end run