Skip to content

Commit

Permalink
Initial commit of work to date.
Browse files Browse the repository at this point in the history
  • Loading branch information
jchambers committed Feb 5, 2017
0 parents commit fd51ec1
Show file tree
Hide file tree
Showing 13 changed files with 342 additions and 0 deletions.
17 changes: 17 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Maven output directories
target

# macOS detritus
.DS_Store

# Eclipse project files
.classpath
.project
.settings

# Things that might appear in the gh-pages branch
_site

# IntelliJ project files
*.iml
.idea/
16 changes: 16 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.eatthepath</groupId>
<artifactId>id-obfuscator</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>ID Obfuscator</name>
<description>A Java library for obfuscating numerical identifiers</description>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
70 changes: 70 additions & 0 deletions src/main/java/com/eatthepath/idobfuscator/AlphabetCodec.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package com.eatthepath.idobfuscator;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

public class AlphabetCodec implements IntegerCodec {

private final char[] alphabet;
private final Map<Character, Integer> charactersToValues = new HashMap<>();

public AlphabetCodec(final char... alphabet) {
Objects.requireNonNull(alphabet, "Alphabet must not be null.");

if (alphabet.length < 2) {
throw new IllegalArgumentException("Alphabet must contain at least two characters");
}

this.alphabet = alphabet;

for (int i = 0; i < alphabet.length; i++) {
this.charactersToValues.put(alphabet[i], i);
}
}

@Override
public String encodeIntegerAsString(final int i) {
final String encodedString;

if (i == 0) {
encodedString = new String(new char[] { this.alphabet[0] });
} else {
long workingCopy = i & 0xffffffffL;
final StringBuilder builder = new StringBuilder();

while (workingCopy != 0) {
builder.insert(0, this.alphabet[(int) (workingCopy % this.alphabet.length)]);
workingCopy /= this.alphabet.length;
}

encodedString = builder.toString();
}

return encodedString;
}

@Override
public int decodeStringAsInteger(final String string) {
final char[] chars = string.toCharArray();
long decoded = 0;
int exponent = chars.length - 1;

for (final char c : chars) {
final int x = this.charactersToValues.get(c);
decoded += x * exponentiate(this.alphabet.length, exponent--);
}

return (int) decoded;
}

static long exponentiate(final int x, final int exponent) {
long exponentiated = 1;

for (int i = 0; i < exponent; i++) {
exponentiated *= x;
}

return exponentiated;
}
}
7 changes: 7 additions & 0 deletions src/main/java/com/eatthepath/idobfuscator/IntegerCodec.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.eatthepath.idobfuscator;

public interface IntegerCodec {
String encodeIntegerAsString(int i);

int decodeStringAsInteger(String string);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.eatthepath.idobfuscator;

public class IntegerObfuscationPipeline {
private final IntegerObfuscator[] obfuscators;
private final IntegerCodec codec;

public IntegerObfuscationPipeline(final IntegerCodec codec, final IntegerObfuscator... obfuscators) {
this.obfuscators = obfuscators;
this.codec = codec;
}

public String obuscate(final int i) {
int encodedInteger = i;

for (final IntegerObfuscator obfuscator : this.obfuscators) {
encodedInteger = obfuscator.obfuscate(encodedInteger);
}

return this.codec.encodeIntegerAsString(encodedInteger);
}

public int deobfuscate(final String string) {
int decodedInteger = this.codec.decodeStringAsInteger(string);

for (int i = this.obfuscators.length - 1; i >= 0; i--) {
decodedInteger = this.obfuscators[i].deobfuscate(decodedInteger);
}

return decodedInteger;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.eatthepath.idobfuscator;

public interface IntegerObfuscator {
int obfuscate(int i);

int deobfuscate(int i);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.eatthepath.idobfuscator;

public class MultiplicativeInverseIntegerObfuscator implements IntegerObfuscator {

final int multiplier;
final int inverse;

public MultiplicativeInverseIntegerObfuscator(final int multiplier) {
if (multiplier <= 0) {
throw new IllegalArgumentException("Multiplier must be positive");
}

this.multiplier = multiplier;
this.inverse = this.getMultiplicativeInverse(multiplier);
}

public int obfuscate(final int i) {
return i * this.multiplier;
}

public int deobfuscate(final int i) {
return i * this.inverse;
}

private int getMultiplicativeInverse(final int multiplier) {
long s = 0, previousS = 1;
long t = 1, previousT = 0;
long r = multiplier, previousR = (1L << Integer.SIZE);

while (r != 0) {
final long q = previousR / r;

{
final long tempR = r;
r = previousR - (q * r);
previousR = tempR;
}

{
final long tempS = s;
s = previousS - (q * s);
previousS = tempS;
}

{
final long tempT = t;
t = previousT - (q * t);
previousT = tempT;
}
}

return (int) previousT;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.eatthepath.idobfuscator;

public class XorIntegerObfuscator implements IntegerObfuscator {

private final int mask;

public XorIntegerObfuscator(final int mask) {
this.mask = mask;
}

@Override
public int obfuscate(final int i) {
return i ^ this.mask;
}

@Override
public int deobfuscate(final int i) {
return i ^ this.mask;
}
}
5 changes: 5 additions & 0 deletions src/main/java/com/eatthepath/idobfuscator/package-info.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/**
* @author <a href="https://github.com/jchambers">Jon Chambers</a>
*
*/
package com.eatthepath.idobfuscator;
41 changes: 41 additions & 0 deletions src/test/java/com/eatthepath/idobfuscator/AlphabetCodecTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.eatthepath.idobfuscator;

import static org.junit.Assert.*;

import org.junit.Test;

public class AlphabetCodecTest {

@Test(expected = NullPointerException.class)
public void testAlphabetCodecNullAlphabet() {
new AlphabetCodec(null);
}

@Test(expected = IllegalArgumentException.class)
public void testAlphabetCodecEmptyAlphabet() {
new AlphabetCodec();
}

@Test(expected = IllegalArgumentException.class)
public void testAlphabetCodecShortAlphabet() {
new AlphabetCodec('a');
}

@Test
public void testEncodeDecodeInteger() {
final AlphabetCodec codec = new AlphabetCodec('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z');
final int[] ids = { 0, 1, 2, 7, 86753, Integer.MAX_VALUE, -77, Integer.MIN_VALUE };

for (final int id : ids) {
assertEquals(id, codec.decodeStringAsInteger(codec.encodeIntegerAsString(id)));
}
}

@Test
public void testExponentiate() {
assertEquals(1, AlphabetCodec.exponentiate(17, 0));
assertEquals(17, AlphabetCodec.exponentiate(17, 1));
assertEquals(289, AlphabetCodec.exponentiate(17, 2));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.eatthepath.idobfuscator;

import static org.junit.Assert.*;

import org.junit.Test;

public class IntegerObfuscationPipelineTest {

private final AlphabetCodec codec = new AlphabetCodec('1', '2', '3', '4', '5', '6', 'a', 'b', 'c', 'd', 'e', 'f');
private final XorIntegerObfuscator xorObfuscator = new XorIntegerObfuscator(3455555);
private final MultiplicativeInverseIntegerObfuscator multiplicativeInverseObfuscator =
new MultiplicativeInverseIntegerObfuscator(873795);

@Test
public void testObfuscateDeobfuscate() {
final IntegerObfuscationPipeline pipeline = new IntegerObfuscationPipeline(this.codec, this.xorObfuscator, this.multiplicativeInverseObfuscator);

for (final int id : new int[] {0, 1, 77, -77, Integer.MAX_VALUE, Integer.MIN_VALUE }) {
assertEquals(id, pipeline.deobfuscate(pipeline.obuscate(id)));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.eatthepath.idobfuscator;

import static org.junit.Assert.*;

import org.junit.Test;

public class MultiplicativeInverseIntegerObfuscatorTest {

@Test(expected = IllegalArgumentException.class)
public void testMultiplicativeInverseIntegerObfuscatorZeroMultiplier() {
new MultiplicativeInverseIntegerObfuscator(0);
}

@Test(expected = IllegalArgumentException.class)
public void testMultiplicativeInverseIntegerObfuscatorNegativeMultiplier() {
new MultiplicativeInverseIntegerObfuscator(-77);
}

@Test
public void testObfuscateDeobfuscate() {
final int[] multipliers = { 77, Integer.MAX_VALUE };
final int[] ids = { 7890, -7458392, Integer.MAX_VALUE, Integer.MIN_VALUE };

for (final int multiplier : multipliers) {
for (final int id : ids) {
final MultiplicativeInverseIntegerObfuscator obfuscator =
new MultiplicativeInverseIntegerObfuscator(multiplier);

assertEquals(id, obfuscator.deobfuscate(obfuscator.obfuscate(id)));
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.eatthepath.idobfuscator;

import static org.junit.Assert.*;

import org.junit.Test;

public class XorIntegerObfuscatorTest {

@Test
public void test() {
for (final int mask : new int[] { 0, 1, -7, 77, Integer.MAX_VALUE, Integer.MIN_VALUE }) {
final XorIntegerObfuscator obfuscator = new XorIntegerObfuscator(mask);

for (final int id : new int[] { 0, 1, -7, 77, Integer.MAX_VALUE, Integer.MIN_VALUE }) {
assertEquals(id, obfuscator.deobfuscate(obfuscator.deobfuscate(id)));
}
}
}
}

0 comments on commit fd51ec1

Please sign in to comment.