// Copyright (C) 2003-2009 by Object Mentor, Inc. All rights reserved.
// Released under the terms of the CPL Common Public License version 1.0.
package fitnesse.authentication;
import fitnesse.util.Base64;
public class HashingCipher implements PasswordCipher {
private static final int repetitions = 3;
private static final String theMagicLock = // A Peom by Yeats.
"Like a long-leggedfly upon the stream\n" +
"His mind moves upon silence.";
@Override
public String encrypt(String value) {
byte[] crypted = repeatEncryption(theMagicLock.getBytes(), value.getBytes());
byte[] squeezed = fillToSize(crypted, 15);
byte[] encoded = Base64.encode(squeezed);
return new String(encoded);
}
private byte[] repeatEncryption(byte[] lock, byte[] key) {
for (int i = 0; i < repetitions; i++)
lock = encrypt(lock, key);
return lock;
}
private byte[] encrypt(byte[] lock, byte[] key) {
int keyIndex = 0;
for (int i = 0; i < lock.length; i++) {
byte lockByte = lock[i];
byte keyByte = key[keyIndex++];
lock[i] = (byte) (lockByte + keyByte);
if (keyIndex == key.length)
keyIndex = 0;
}
return lock;
}
public byte[] fillToSize(byte[] input, int size) {
byte[] bytes = new byte[size];
int inputLength = input.length;
int inputIndex = 0;
int outputIndex = 0;
if (inputLength <= size) {
while (outputIndex < size) {
bytes[outputIndex++] = input[inputIndex++];
if (inputIndex == inputLength)
inputIndex = 0;
}
} else {
while (inputIndex < inputLength) {
byte currentByte = bytes[outputIndex];
bytes[outputIndex++] = (byte) (currentByte + input[inputIndex++]);
if (outputIndex == size)
outputIndex = 0;
}
}
return bytes;
}
}