diff --git a/common/pom.xml b/common/pom.xml index 6715f805c7..114fac1725 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -23,6 +23,10 @@ com.michael-bull.kotlin-inline-logger kotlin-inline-logger-jvm + + io.netty + netty-buffer + org.bouncycastle bcprov-jdk15on diff --git a/common/src/main/java/dev/openrs2/common/crypto/Rsa.kt b/common/src/main/java/dev/openrs2/common/crypto/Rsa.kt index fa27e02dba..964c8904ac 100644 --- a/common/src/main/java/dev/openrs2/common/crypto/Rsa.kt +++ b/common/src/main/java/dev/openrs2/common/crypto/Rsa.kt @@ -1,5 +1,7 @@ package dev.openrs2.common.crypto +import io.netty.buffer.ByteBuf +import io.netty.buffer.Unpooled import org.bouncycastle.asn1.DERNull import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers import org.bouncycastle.asn1.pkcs.PrivateKeyInfo @@ -22,6 +24,30 @@ import java.math.BigInteger import java.nio.file.Files import java.nio.file.Path +private fun ByteBuf.toBigInteger(): BigInteger { + val bytes: ByteArray + if (hasArray() && arrayOffset() == 0 && readerIndex() == 0 && readableBytes() == array().size) { + bytes = array() + } else { + bytes = ByteArray(readableBytes()) + getBytes(readerIndex(), bytes) + } + + return BigInteger(bytes) +} + +private fun BigInteger.toByteBuf(): ByteBuf { + return Unpooled.wrappedBuffer(toByteArray()) +} + +fun ByteBuf.rsaEncrypt(key: RSAKeyParameters): ByteBuf { + return Rsa.encrypt(toBigInteger(), key).toByteBuf() +} + +fun ByteBuf.rsaDecrypt(key: RSAKeyParameters): ByteBuf { + return Rsa.decrypt(toBigInteger(), key).toByteBuf() +} + object Rsa { private const val PUBLIC_KEY = "PUBLIC KEY" private const val PRIVATE_KEY = "PRIVATE KEY" diff --git a/common/src/test/java/dev/openrs2/common/crypto/RsaTest.kt b/common/src/test/java/dev/openrs2/common/crypto/RsaTest.kt index 24093549b9..c4b6317620 100644 --- a/common/src/test/java/dev/openrs2/common/crypto/RsaTest.kt +++ b/common/src/test/java/dev/openrs2/common/crypto/RsaTest.kt @@ -1,5 +1,6 @@ package dev.openrs2.common.crypto +import io.netty.buffer.Unpooled import org.bouncycastle.crypto.params.RSAKeyParameters import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters import org.bouncycastle.util.Properties @@ -54,6 +55,52 @@ object RsaTest { assertEquals(BigInteger("65"), ciphertext) } + @Test + fun testEncryptByteBuf() { + // from https://en.wikipedia.org/wiki/RSA_(cryptosystem)#Example + val public = allowUnsafeMod { RSAKeyParameters(false, BigInteger("3233"), BigInteger("17")) } + + val plaintext = Unpooled.wrappedBuffer(byteArrayOf(65)) + try { + val ciphertext = plaintext.rsaEncrypt(public) + try { + val expectedCiphertext = Unpooled.wrappedBuffer(byteArrayOf(10, 230.toByte())) + try { + assertEquals(expectedCiphertext, ciphertext) + } finally { + expectedCiphertext.release() + } + } finally { + ciphertext.release() + } + } finally { + plaintext.release() + } + } + + @Test + fun testDecryptByteBuf() { + // from https://en.wikipedia.org/wiki/RSA_(cryptosystem)#Example + val private = allowUnsafeMod { RSAKeyParameters(true, BigInteger("3233"), BigInteger("413")) } + + val ciphertext = Unpooled.wrappedBuffer(byteArrayOf(10, 230.toByte())) + try { + val plaintext = ciphertext.rsaDecrypt(private) + try { + val expectedPlaintext = Unpooled.wrappedBuffer(byteArrayOf(65)) + try { + assertEquals(expectedPlaintext, plaintext) + } finally { + expectedPlaintext.release() + } + } finally { + plaintext.release() + } + } finally { + ciphertext.release() + } + } + private fun allowUnsafeMod(f: () -> T): T { Properties.setThreadOverride(ALLOW_UNSAFE_MOD, true) try { diff --git a/pom.xml b/pom.xml index 336e1eb8df..759f61112a 100644 --- a/pom.xml +++ b/pom.xml @@ -83,6 +83,11 @@ pack200 1.0.2 + + io.netty + netty-buffer + 4.1.44.Final + org.bouncycastle bcprov-jdk15on