/* * Copyright (c) 2013 Allogy Interactive. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.allogy.encryption; public class SmsCrypto { private static int[] num35s = new int[6]; // note the integer must be a positive number between 1 and 35 private static char IntToChar(int num) { if (num < 0 || num > 32) { throw new IllegalArgumentException("got: " + num); } if (num <= 9) { return (char) ('0' + num); } char retval = (char) ('a' + num - 10); if (retval == 'l') return 'L'; return retval; } private static int CharToInt(char c) { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'a' && c <= 'z') return c - 'a' + 10; if (c == 'L') return 'L' - 'A' + 10; throw new IllegalArgumentException("got: " + c); } private static int map(int accum, int value, int inputPosition, int outputPosition) { return accum | ((value >> inputPosition) & 0x1) << outputPosition; } // note: x and y must be positive // x can be up to a 15 bit integer public static String encode(int x, long salt) { // NB: a kludge to help out the weak 32-bit PHP server installation... String salt_s = Long.toString(salt); int salt_l = salt_s.length(); if (salt_l > 9) { salt = Long.parseLong(salt_s.substring(salt_l - 9)); } if ((x & 0x8000) != 0) { // using the high bit might work, but still... throw new IllegalArgumentException("input too large: " + x); } // fold the salt in half (it may be a big number), make sure the first // bit is zero. int y = (int) (((salt >> 16) & 0xFFFF) ^ (salt & 0xFFFF)) & 0x7FFF; // System.err.println("y="+y); // constant initialization number int initNum = 23145; int xor1 = x ^ initNum; // System.err.println("xor1=0x"+Integer.toHexString(xor1)); // 14 check bits (30bits(final)-16bit(input) int checkBits = xor1 & 0x3FFF; // System.err.println("checkBits=0x"+Integer.toHexString(checkBits)); int y2 = 0; y2 = map(y2, xor1, 4, 0); y2 = map(y2, xor1, 9, 1); y2 = map(y2, xor1, 5, 2); y2 = map(y2, xor1, 3, 3); y2 = map(y2, xor1, 14, 4); y2 = map(y2, xor1, 6, 5); y2 = map(y2, xor1, 2, 6); y2 = map(y2, xor1, 13, 7); y2 = map(y2, xor1, 7, 8); y2 = map(y2, xor1, 12, 9); y2 = map(y2, xor1, 1, 10); y2 = map(y2, xor1, 11, 11); y2 = map(y2, xor1, 8, 12); y2 = map(y2, xor1, 10, 13); y2 = map(y2, xor1, 0, 14); y2 = map(y2, xor1, 15, 15); // System.err.println("y2=0x"+Integer.toHexString(y2)); int z1 = (y2 + y); // System.err.println("Z1=0x"+Integer.toHexString(z1)); int z = 0; z = map(z, z1, 0, 2); z = map(z, z1, 1, 11); z = map(z, z1, 2, 19); z = map(z, z1, 3, 26); z = map(z, z1, 4, 29); z = map(z, z1, 5, 6); z = map(z, z1, 6, 15); z = map(z, z1, 7, 23); z = map(z, z1, 8, 8); z = map(z, z1, 9, 3); z = map(z, z1, 10, 0); z = map(z, z1, 11, 13); z = map(z, z1, 12, 17); z = map(z, z1, 13, 21); z = map(z, z1, 14, 27); z = map(z, z1, 15, 4); z = map(z, checkBits, 0, 28); z = map(z, checkBits, 1, 1); z = map(z, checkBits, 2, 9); z = map(z, checkBits, 3, 16); z = map(z, checkBits, 4, 20); z = map(z, checkBits, 5, 18); z = map(z, checkBits, 6, 22); z = map(z, checkBits, 7, 14); z = map(z, checkBits, 8, 12); z = map(z, checkBits, 9, 10); z = map(z, checkBits, 10, 24); z = map(z, checkBits, 11, 7); z = map(z, checkBits, 12, 5); z = map(z, checkBits, 13, 25); // System.err.println("Z=0x"+Integer.toHexString((int)z)); StringBuilder sb = new StringBuilder(); // Convert the final integer 'z' to a six-character code-string for (int i = 0; i < 6; i++) { // 0-31 is five bits, as is 0x1F int lessThan32 = z & 0x1F; char c = IntToChar(lessThan32); // System.err.println("_z="+lessThan32+"\t-> "+c); sb.insert(0, c); // shift-out five bits and continue converting. z = z >> 5; } return sb.toString(); } // note: z is a 5 character long string and y must be a positive integer public static int decode(String code, long salt) throws InvalidCodeException { // NB: a kludge to help out the weak 32-bit PHP server installation... { String salt_s = Long.toString(salt); int salt_l = salt_s.length(); if (salt_l > 9) { salt = Long.parseLong(salt_s.substring(salt_l - 9)); } } // fold the salt in half (it may be a big number), make sure the first // bit is zero. int y = (int) (((salt >> 16) & 0xFFFF) ^ (salt & 0xFFFF)) & 0x7FFF; // Convert the code-string into the integer 'z' int z = 0; for (int i = 0; i < 6; i++) { char c = code.charAt(i); int lessThan32 = CharToInt(c); // System.err.println("+z="+lessThan32+"\t<-- "+c); z = z << 5 | lessThan32; } // System.err.println("Z=0x"+Integer.toHexString((int)z)); int checkBits = 0; int z1 = 0; z1 = map(z1, z, 2, 0); z1 = map(z1, z, 11, 1); z1 = map(z1, z, 19, 2); z1 = map(z1, z, 26, 3); z1 = map(z1, z, 29, 4); z1 = map(z1, z, 6, 5); z1 = map(z1, z, 15, 6); z1 = map(z1, z, 23, 7); z1 = map(z1, z, 8, 8); z1 = map(z1, z, 3, 9); z1 = map(z1, z, 0, 10); z1 = map(z1, z, 13, 11); z1 = map(z1, z, 17, 12); z1 = map(z1, z, 21, 13); z1 = map(z1, z, 27, 14); z1 = map(z1, z, 4, 15); checkBits = map(checkBits, z, 28, 0); checkBits = map(checkBits, z, 1, 1); checkBits = map(checkBits, z, 9, 2); checkBits = map(checkBits, z, 16, 3); checkBits = map(checkBits, z, 20, 4); checkBits = map(checkBits, z, 18, 5); checkBits = map(checkBits, z, 22, 6); checkBits = map(checkBits, z, 14, 7); checkBits = map(checkBits, z, 12, 8); checkBits = map(checkBits, z, 10, 9); checkBits = map(checkBits, z, 24, 10); checkBits = map(checkBits, z, 7, 11); checkBits = map(checkBits, z, 5, 12); checkBits = map(checkBits, z, 25, 13); // System.err.println("Z1=0x"+Integer.toHexString(z1)); // System.err.println("checkBits=0x"+Integer.toHexString(checkBits)); int y2 = (z1 - y); // System.err.println("y2=0x"+Integer.toHexString(y2)); int xor1 = 0; xor1 = map(xor1, y2, 0, 4); xor1 = map(xor1, y2, 1, 9); xor1 = map(xor1, y2, 2, 5); xor1 = map(xor1, y2, 3, 3); xor1 = map(xor1, y2, 4, 14); xor1 = map(xor1, y2, 5, 6); xor1 = map(xor1, y2, 6, 2); xor1 = map(xor1, y2, 7, 13); xor1 = map(xor1, y2, 8, 7); xor1 = map(xor1, y2, 9, 12); xor1 = map(xor1, y2, 10, 1); xor1 = map(xor1, y2, 11, 11); xor1 = map(xor1, y2, 12, 8); xor1 = map(xor1, y2, 13, 10); xor1 = map(xor1, y2, 14, 0); xor1 = map(xor1, y2, 15, 15); // System.err.println("xor1=0x"+Integer.toHexString(xor1)); if (((xor1 ^ checkBits) & 0x3FFF) != 0) { throw new InvalidCodeException(code); } // constant initialization number int initNum = 23145; int x = xor1 ^ initNum; return x; } }