package com.perforce.p4java.impl.mapbased.rpc.func.client; import java.io.UnsupportedEncodingException; import java.util.Arrays; import com.perforce.p4java.CharsetDefs; import com.perforce.p4java.exception.NullPointerError; import com.perforce.p4java.exception.P4JavaError; /** * Java equivalent of mangle.cc * * @author Kevin Sawicki (ksawicki@perforce.com) * */ final class Mangle { private static final int BPB = 8; private int[] o = new int[8]; private int[] pr = new int[8]; private int[] s0 = new int[16]; private int[] s1 = new int[16]; private int[] s2 = new int[8]; /** * Create a new mangle */ protected Mangle() { // diffusion pattern o[0] = 7; o[1] = 6; o[2] = 2; o[3] = 1; o[4] = 5; o[5] = 0; o[6] = 3; o[7] = 4; // inverse of fixed permutation pr[0] = 2; pr[1] = 5; pr[2] = 4; pr[3] = 0; pr[4] = 3; pr[5] = 1; pr[6] = 7; pr[7] = 6; // S-box permutations s0[0] = 12; s0[1] = 15; s0[2] = 7; s0[3] = 10; s0[4] = 14; s0[5] = 13; s0[6] = 11; s0[7] = 0; s0[8] = 2; s0[9] = 6; s0[10] = 3; s0[11] = 1; s0[12] = 9; s0[13] = 4; s0[14] = 5; s0[15] = 8; s1[0] = 7; s1[1] = 2; s1[2] = 14; s1[3] = 9; s1[4] = 3; s1[5] = 11; s1[6] = 0; s1[7] = 4; s1[8] = 12; s1[9] = 13; s1[10] = 1; s1[11] = 10; s1[12] = 6; s1[13] = 15; s1[14] = 8; s1[15] = 5; // S-box mix s2[0] = 10; s2[1] = 1; s2[2] = 13; s2[3] = 12; s2[4] = 4; s2[5] = 0; s2[6] = 11; s2[7] = 3; } /** * Copy of strops::OtoX * * @param o * @return - char */ private static char OtoX(char o) { return (char) (o >= 10 ? o - 10 + 'A' : o + '0'); }; private String OtoX(String octet) { StringBuilder hex = new StringBuilder(); for (int i = 0; i < octet.length(); i++) { hex.append(OtoX((char) ((octet.charAt(i) >> 4) & 0x0f))); hex.append(OtoX((char) ((octet.charAt(i) >> 0) & 0x0f))); } return hex.toString(); } /** * Take a bunch of bytes and translate it into a hex string. No real * error checking done. */ protected String OtoX(byte[] octets) { if (octets == null) { throw new NullPointerError("null octets byte array in Mangle.OtoX"); } StringBuilder strBldr = new StringBuilder(); for (int i = 0; i < octets.length; i++) { strBldr.append(OtoX((char) ((octets[i] >> 4) & 0x0F))); strBldr.append(OtoX((char) ((octets[i] >> 0) & 0x0F))); } return strBldr.toString(); } /** * Turn a hex string into an array of bytes (octets). Little to no * useful error checking. * * @param hex the hex-encoded string to be converted */ protected static byte[] XtoO(String hex) { if ((hex == null) || ((hex.length() / 2) == 0)) { throw new P4JavaError("bad XtoO conversion parameters"); } byte[] octets = new byte[hex.length() / 2]; int i = 0; int j = 0; while ((i < hex.length()) && (j < octets.length)) { octets[j] = (byte) ((byte) ((XtoO(hex.charAt(i)) &0X0F) << 4) | ((byte) (XtoO(hex.charAt(i + 1)) &0X0F))); i += 2; j++; } return octets; } protected static byte XtoO(char c) { return (byte) (c - ( c > '9' ? ( c >= 'a' ? 'a' - 10 : 'A' - 10 ) : '0')); } /** * Do an XOR on the passed-in 32 char hex strings (e.g. typical MD5 hash outputs); * return the result as a 32 char hex string. Little to no real error * checking performed. */ protected String xor32(String data, String key) { if ((data == null) || (key == null) || (data.length() != 32) || (key.length() != 32)) { throw new P4JavaError("bad parameters to Mangle.xor32"); } byte[] dataBytes = XtoO(data); byte[] keyBytes = XtoO(key); byte[] resultBytes = new byte[16]; for (int i = 0; i < resultBytes.length; i++) { resultBytes[i] = (byte) (dataBytes[i] ^ keyBytes[i]); } return OtoX(resultBytes); } /** * Loop over the data string, mangle it a chunk at a time, and thus can now * handle passwords longer than 16 characters. * * @param data * @param key * @param digest * @return enrypted string * @throws UnsupportedEncodingException */ protected String encrypt(String data, String key) throws UnsupportedEncodingException { StringBuffer mangledValue = new StringBuffer(); // Proper handling of unicode characters byte[] dataBytes = data.getBytes(CharsetDefs.UTF8.name()); int inputLen = dataBytes.length; int offset = 0; char[] dataChars = new char[inputLen]; for (int i=0; i<dataBytes.length; i++) { dataChars[i] = (char)dataBytes[i]; } while (offset < inputLen) { int chunkSize = inputLen - offset; if (chunkSize > 16) { chunkSize = 16; } String chunkData = new String(dataChars, offset, chunkSize); String mangledChunk = mangle(chunkData, key, false); mangledValue.append(mangledChunk); offset += chunkSize; } return mangledValue.toString(); } /** * Mangle data and key and return mangled string * * @param data * @param key * @return - mangled string */ protected String mangle(String data, String key, boolean digest) { int[] m = new int[128]; int[] k = new int[128]; StringBuilder p, q; char[] src = new char[16]; char[] enc = new char[16]; char[] buf = new char[16]; int counter; int output; int c, i, j; String mangled = null; if ((key == null) || (data == null)) { throw new NullPointerError("null argument in mangle()"); } if (!digest && data.length() > 16) { return mangled; } Arrays.fill(src, (char) 0); Arrays.fill(enc, (char) 0); Arrays.fill(buf, (char) 0); // truncate key to 16 character max System.arraycopy(key.toCharArray(), 0, buf, 0, key.length() > 16 ? 16 : key.length()); if (digest) { byte[] srcBytes = XtoO(data); for (int z = 0; z < srcBytes.length; z++) { src[z] = (char) srcBytes[z]; }; } else { System.arraycopy(data.toCharArray(), 0, src, 0, data.length()); } p = new StringBuilder(); p.append(src); q = new StringBuilder(); q.append(enc); for (counter = 0; counter < 16; counter += 1) { c = buf[counter] & 0xFF; for (i = 0; i < BPB; i += 1) { k[(BPB * counter) + i] = c & 0x1; c = c >> 1; } } counter = 0; int qIndex = 0; for (j = 0; j < 16; ++j) { c = p.charAt(j); if (counter == 16) { Getdval(m, k); for (counter = 0; counter < 16; counter += 1) { output = 0; for (i = BPB - 1; i >= 0; i -= 1) { output = (output << 1) + m[(BPB * counter) + i]; } q.setCharAt(qIndex, (char) output); qIndex++; } counter = 0; } for (i = 0; i < BPB; i += 1) { m[(BPB * counter) + i] = c & 0x1; c = c >> 1; } counter += 1; } for (; counter < 16; counter += 1) { for (i = 0; i < BPB; i += 1) { m[(BPB * counter) + i] = 0; } } Getdval(m, k); for (counter = 0; counter < 16; counter += 1) { output = 0; for (i = BPB - 1; i >= 0; i -= 1) { output = (output << 1) + m[(BPB * counter) + i]; } q.setCharAt(qIndex, (char) output); qIndex++; } mangled = OtoX(q.toString()); return mangled; } private void Getdval(int m[], int k[]) { int tcbindex, tcbcontrol; /* transfer control byte indices */ int round, hi, lo, h_0, h_1; int bit, temp1; int _byte, index, v; int[] tr = new int[BPB]; h_0 = 0; h_1 = 1; tcbcontrol = 0; for (round = 0; round < 16; round += 1) { tcbindex = tcbcontrol; for (_byte = 0; _byte < 8; _byte += 1) { lo = (m[(h_1 * 64) + (BPB * _byte) + 7]) * 8 + (m[(h_1 * 64) + (BPB * _byte) + 6]) * 4 + (m[(h_1 * 64) + (BPB * _byte) + 5]) * 2 + (m[(h_1 * 64) + (BPB * _byte) + 4]); hi = (m[(h_1 * 64) + (BPB * _byte) + 3]) * 8 + (m[(h_1 * 64) + (BPB * _byte) + 2]) * 4 + (m[(h_1 * 64) + (BPB * _byte) + 1]) * 2 + (m[(h_1 * 64) + (BPB * _byte) + 0]); v = (s0[lo] + 16 * s1[hi]) * (1 - k[(BPB * tcbindex) + _byte]) + (s0[hi] + 16 * s1[lo]) * k[(BPB * tcbindex) + _byte]; for (temp1 = 0; temp1 < BPB; temp1 += 1) { tr[temp1] = v & 0x1; v = v >> 1; } for (bit = 0; bit < BPB; bit += 1) { index = (o[bit] + _byte) & 0x7; temp1 = m[(h_0 * 64) + (BPB * index) + bit] + k[(BPB * tcbcontrol) + pr[bit]] + tr[pr[bit]]; m[(h_0 * 64) + (BPB * index) + bit] = temp1 & 0x1; } if (_byte < 7) tcbcontrol = (tcbcontrol + 1) & 0xF; } temp1 = h_0; h_0 = h_1; h_1 = temp1; } /* final swap */ for (_byte = 0; _byte < 8; _byte += 1) { for (bit = 0; bit < BPB; bit += 1) { temp1 = m[(BPB * _byte) + bit]; m[(BPB * _byte) + bit] = m[64 + (BPB * _byte) + bit]; m[64 + (BPB * _byte) + bit] = temp1; } } } }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 19903 | stuartrowe |
Branching //guest/perforce_software/p4java/... to //guest/stuartrowe/p4java/... |
||
//guest/perforce_software/p4java/r14.1/src/main/java/com/perforce/p4java/impl/mapbased/rpc/func/client/Mangle.java | |||||
#1 | 12541 | Matt Attaway | Initial add of the 14.1 p4java source code |