/* * File : Encryption.java * Created : 03-jul-2001 09:51 * By : allastar * * JClic - Authoring and playing system for educational activities * * Copyright (C) 2000 - 2018 Francesc Busquets & Departament * d'Educacio de la Generalitat de Catalunya * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details (see the LICENSE file). */ package edu.xtec.util; /** * Utilities to encrypt and decrypt strings using simple methods, just to avoid * write passwords in plain text in data and configuration files. Do not use it * as a secure cryptographic system! * * @author Albert Llastarri (allastar@xtec.cat) * @version 13.08.08 */ public final class Encryption { private static final String BLANK = "___blank___##"; public static String Encrypt(String txt) { if (txt == null || txt.length() == 0) txt = BLANK; String result = null; try { result = codify(txt); } catch (Exception ex) { System.err.println("Error encripting text!"); } return result; } public static String Decrypt(String txt) { if (txt == null || txt.length() == 0) return null; String s = decodify(txt); if (BLANK.equals(s)) s = new String(); return s; } private static char hexCharArrayToChar(char[] cA, int fromIndex) { char[] hex = new char[4]; int n = 0; for (int i = 0; i <= 3; i++) { int j = Character.digit(cA[fromIndex + i], 16); n = (n * 16) + j; } return (char) n; } private static char[] charToHexCharArray(char c) { char[] hex = new char[4]; int j = (int) c; for (int i = 3; i >= 0; i--) { hex[i] = Character.forDigit(j % 16, 16); j /= 16; } return hex; } private static char[] intToHexCharArray(int c) { char[] hex = new char[2]; int j = (int) c; for (int i = 1; i >= 0; i--) { hex[i] = Character.forDigit(j % 16, 16); j /= 16; } return hex; } private static int hexCharArrayToInt(char[] cA, int fromIndex) { int n = 0; for (int i = 0; i <= 1; i++) { int j = Character.digit(cA[fromIndex + i], 16); n = (n * 16) + j; } return n; } private static StringBuilder compressZeros(char[] cA) { int total = 0; StringBuilder sb = new StringBuilder(cA.length); int[] zeros = new int[(cA.length + 7) / 8]; // it will be better to use bytes, but // then it takes the first bit as a sign int j; for (j = 0; total < cA.length; j++) { char b = 0; for (int i = 0; i <= 7; i++) { b <<= 1; if (total < cA.length) { if (cA[total] == '0') b += 1; else sb.append(cA[total]); } total++; } zeros[j] = (int) b; } return codifyZerosField(zeros, j).append(sb.substring(0)); } private static StringBuilder codifyZerosField(int[] zeros, int length) { String hexZeros = codifyToHex(zeros, length); // hexZeros size is always odd StringBuilder codified = new StringBuilder(); if (hexZeros.length() > 1) { char c1 = hexZeros.charAt(0); char c2 = hexZeros.charAt(1); int num = 1; int currentChar = 2; while (currentChar < hexZeros.length()) { if (c1 == hexZeros.charAt(currentChar) && c2 == hexZeros.charAt(currentChar + 1) && num < 32) num++; else { // New sequence codified.append(Character.forDigit(num, 32)); codified.append(c1); codified.append(c2); num = 1; c1 = hexZeros.charAt(currentChar); c2 = hexZeros.charAt(currentChar + 1); } currentChar += 2; } codified.append(Character.forDigit(num, 32)); codified.append(c1); codified.append(c2); codified.append("0"); } return codified; } private static String decodifyZerosField(char[] cA) { StringBuilder sb = new StringBuilder(); int num = Character.digit(cA[0], 32); int k = 0; int i; for (i = 0; num != 0; i++) { while (num > 0) { sb.append(cA[(i * 3) + 1]); sb.append(cA[(i * 3) + 2]); num--; k++; } if (cA.length > ((i * 3) + 3)) num = Character.digit(cA[(i * 3) + 3], 32); else num = 0; } for (int j = (i * 3) + 1; j < cA.length; j++) sb.append(cA[j]); char c = Character.forDigit(k, 32); return c + sb.toString(); } private static StringBuilder decompressZeros(char[] cA) { cA = decodifyZerosField(cA).toCharArray(); int numBytesZeros = Character.digit(cA[0], 32); int iniNoZeros = (numBytesZeros * 2) + 1; boolean bFi = false; StringBuilder sb = new StringBuilder(); for (int i = 0; i < numBytesZeros && !bFi; i++) { int zeros = hexCharArrayToInt(cA, 1 + (i * 2)); String s = Integer.toBinaryString(zeros); while (s.length() < 8) s = "0" + s; for (int j = 0; j <= 7 && !bFi; j++) { if (s.charAt(j) == '1') { sb.append('0'); } else if (iniNoZeros < cA.length) { sb.append(cA[iniNoZeros]); iniNoZeros++; } else bFi = true; } } return sb; } private static String codifyToHex(int[] bA, int length) { // char [] cA=s.toCharArray(); char[] cA = new char[length * 2]; int j = 0; for (int i = 0; i < length; i++) { char[] hex = intToHexCharArray(bA[i]); for (int k = 0; k < 2; k++) { cA[j] = hex[k]; j++; } } String st = new String(cA); return st; } private static char[] codifyToHex(String s) { char[] cA = new char[s.length() * 4]; int j = 0; for (int i = 0; i < s.length(); i++) { char[] hex = charToHexCharArray(s.charAt(i)); for (int k = 0; k < 4; k++) { cA[j] = hex[k]; j++; } } return cA; } private static String decodifyFromHex(StringBuilder sb1) { StringBuilder sb = new StringBuilder(); char[] cA = sb1.toString().toCharArray(); int j = 0; for (int i = 0; j < sb1.length(); i++) { char c = hexCharArrayToChar(cA, j); sb.append(c); j += 4; } return sb.toString(); } private static char[] changeOrder(StringBuilder s) { int m = 0; int n = s.length() - 1; char[] cA = new char[s.length()]; // =s.toCharArray(); for (int i = 0; i < s.length(); i++) { if ((i % 2) == 0) { cA[m] = s.charAt(i); m++; } else { cA[n] = s.charAt(i); n--; } } return cA; } private static char[] unchangeOrder(String s) { int m = 0; int n = s.length() - 1; char[] cA = new char[s.length()]; for (int i = 0; i < s.length(); i++) { if ((i % 2) == 0) { cA[i] = s.charAt(m); m++; } else { cA[i] = s.charAt(n); n--; } } return cA; } static class TooLargePasswordException extends Exception { @Override public String toString() { return "Password mustn't contain over 24 characters!!!"; } } private static String codify(String word) throws TooLargePasswordException { if (word.length() > 24) throw new TooLargePasswordException(); return new String(changeOrder(compressZeros(codifyToHex(word)))); } private static String decodify(String word) { try { return decodifyFromHex(decompressZeros(unchangeOrder(word))); } catch (Exception e) { // The supplied word was not codified using this system return ""; } } }