mirror of
https://git.krews.org/morningstar/Arcturus-Community.git
synced 2025-01-19 07:56:26 +01:00
169 lines
5.1 KiB
Java
169 lines
5.1 KiB
Java
package com.eu.habbo.crypto;
|
|
|
|
import com.eu.habbo.crypto.exceptions.HabboCryptoException;
|
|
import com.eu.habbo.crypto.utils.BigIntegerUtils;
|
|
import org.apache.commons.lang3.mutable.MutableInt;
|
|
|
|
import java.io.ByteArrayOutputStream;
|
|
import java.io.IOException;
|
|
import java.math.BigInteger;
|
|
import java.util.concurrent.ThreadLocalRandom;
|
|
|
|
public class HabboRSACrypto {
|
|
|
|
private final BigInteger e;
|
|
private final BigInteger n;
|
|
private final BigInteger d;
|
|
private final int blockSize;
|
|
|
|
public HabboRSACrypto(String e, String n) {
|
|
this.e = new BigInteger(e, 16);
|
|
this.n = new BigInteger(n, 16);
|
|
this.d = null;
|
|
this.blockSize = (this.n.bitLength() + 7) / 8;
|
|
}
|
|
|
|
public HabboRSACrypto(String e, String n, String d) {
|
|
this.e = new BigInteger(e, 16);
|
|
this.n = new BigInteger(n, 16);
|
|
this.d = new BigInteger(d, 16);
|
|
this.blockSize = (this.n.bitLength() + 7) / 8;
|
|
}
|
|
|
|
public byte[] Encrypt(byte[] data) throws HabboCryptoException {
|
|
return DoEncrypt(data, true, 2);
|
|
}
|
|
|
|
public byte[] Decrypt(byte[] data) throws HabboCryptoException {
|
|
return DoDecrypt(data, false, 2);
|
|
}
|
|
|
|
public byte[] Sign(byte[] data) throws HabboCryptoException {
|
|
return DoEncrypt(data, false, 1);
|
|
}
|
|
|
|
public byte[] Verify(byte[] data) throws HabboCryptoException {
|
|
return DoDecrypt(data, true, 1);
|
|
}
|
|
|
|
private BigInteger DoPublic(BigInteger x) {
|
|
return x.modPow(this.e, this.n);
|
|
}
|
|
|
|
private BigInteger DoPrivate(BigInteger x) {
|
|
return x.modPow(this.d, this.n);
|
|
}
|
|
|
|
private byte[] DoEncrypt(byte[] data, boolean isPublic, int padType) throws HabboCryptoException {
|
|
try (ByteArrayOutputStream dst = new ByteArrayOutputStream()) {
|
|
int bl = this.blockSize;
|
|
int end = data.length;
|
|
MutableInt pos = new MutableInt(0);
|
|
|
|
while (pos.intValue() < end) {
|
|
byte[] padded = Pkcs1Pad(data, pos, end, bl, padType);
|
|
BigInteger block = new BigInteger(padded);
|
|
BigInteger chunk = isPublic ? DoPublic(block) : DoPrivate(block);
|
|
|
|
for (int b = (int) (bl - Math.ceil(chunk.bitLength() / 8.0)); b > 0; --b) {
|
|
dst.write(0x00);
|
|
}
|
|
|
|
dst.write(BigIntegerUtils.toUnsignedByteArray(chunk));
|
|
}
|
|
|
|
return dst.toByteArray();
|
|
} catch (IOException e) {
|
|
throw new HabboCryptoException(e);
|
|
}
|
|
}
|
|
|
|
private byte[] DoDecrypt(byte[] data, boolean isPublic, int padType) throws HabboCryptoException {
|
|
if (data.length % this.blockSize != 0) {
|
|
throw new HabboCryptoException("Decryption data was not in blocks of " + this.blockSize + " bytes, total " + data.length + ".");
|
|
}
|
|
|
|
try (ByteArrayOutputStream dst = new ByteArrayOutputStream()) {
|
|
int end = data.length;
|
|
int pos = 0;
|
|
|
|
while (pos < end) {
|
|
byte[] blockData = new byte[this.blockSize];
|
|
System.arraycopy(data, pos, blockData, 0, this.blockSize);
|
|
|
|
BigInteger block = new BigInteger(1, blockData);
|
|
BigInteger chunk = isPublic ? DoPublic(block) : DoPrivate(block);
|
|
byte[] unpadded = Pkcs1Unpad(chunk.toByteArray(), this.blockSize, padType);
|
|
|
|
pos += this.blockSize;
|
|
dst.write(unpadded);
|
|
}
|
|
|
|
return dst.toByteArray();
|
|
} catch (IOException e) {
|
|
throw new HabboCryptoException(e);
|
|
}
|
|
}
|
|
|
|
private static byte[] Pkcs1Pad(byte[] src, MutableInt pos, int end, int n, int padType) {
|
|
byte[] result = new byte[n];
|
|
int p = pos.intValue();
|
|
end = Math.min(end, Math.min(src.length, p + n - 11));
|
|
pos.setValue(end);
|
|
int i = end - 1;
|
|
|
|
while (i >= p && n > 11) {
|
|
result[--n] = src[i--];
|
|
}
|
|
|
|
result[--n] = 0;
|
|
|
|
if (padType == 2) {
|
|
while (n > 2) {
|
|
result[--n] = (byte) ThreadLocalRandom.current().nextInt(1, 256);
|
|
}
|
|
} else {
|
|
while (n > 2) {
|
|
result[--n] = (byte) 0xFF;
|
|
}
|
|
}
|
|
|
|
result[--n] = (byte) padType;
|
|
result[--n] = 0;
|
|
|
|
return result;
|
|
}
|
|
|
|
private static byte[] Pkcs1Unpad(byte[] b, int n, int padType) throws HabboCryptoException {
|
|
byte[] result = new byte[n];
|
|
int resultPos = 0;
|
|
int i = 0;
|
|
|
|
while (i < b.length && b[i] == 0) {
|
|
++i;
|
|
}
|
|
|
|
if (b.length - i != n - 1 || b[i] != padType) {
|
|
throw new HabboCryptoException("PKCS#1 unpad: i=" + i + ", expected b[i]==" + padType + ", got b[i]=" + b[i]);
|
|
}
|
|
|
|
++i;
|
|
|
|
while (b[i] != 0) {
|
|
if (++i >= b.length) {
|
|
throw new HabboCryptoException("PKCS#1 unpad: i=" + i + ", b[i-1]!=0 (=" + b[i-1] + ")");
|
|
}
|
|
}
|
|
|
|
while (++i < b.length) {
|
|
result[resultPos++] = b[i];
|
|
}
|
|
|
|
byte[] resultCopy = new byte[resultPos];
|
|
System.arraycopy(result, 0, resultCopy, 0, resultPos);
|
|
|
|
return resultCopy;
|
|
}
|
|
|
|
}
|