-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Custom data pre-processing (currently includes No-Op and AES e2e encryption) * LZ4 frame compression
- Loading branch information
Showing
11 changed files
with
218 additions
and
41 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package com.austinv11.persistence; | ||
|
||
import javax.annotation.Nonnull; | ||
|
||
/** | ||
* This represents a custom preprocessor which mutates data before consumption and mutates data before packaging. | ||
*/ | ||
public interface PreProcessor { | ||
|
||
/** | ||
* A unique key for this pre processor type. | ||
* | ||
* @return The key for the pre-processor. | ||
*/ | ||
byte getKey(); | ||
|
||
/** | ||
* Called to pack data to be sent. | ||
* | ||
* @param host The host this data belongs to. | ||
* @param port The port from the provided host this data belongs to. | ||
* @param input The data to pack. | ||
* @return The packed data. | ||
*/ | ||
@Nonnull | ||
byte[] pack(@Nonnull String host, int port, @Nonnull byte[] input); | ||
|
||
/** | ||
* Called to consume data received. | ||
* | ||
* @param host The host this data belongs to. | ||
* @param port The port from the provided host this data belongs to. | ||
* @param input The data to consume. | ||
* @return The processed data. | ||
*/ | ||
@Nonnull | ||
byte[] consume(@Nonnull String host, int port, @Nonnull byte[] input); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
72 changes: 72 additions & 0 deletions
72
src/main/kotlin/com/austinv11/persistence/impl/EncryptedPreProcessor.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
package com.austinv11.persistence.impl | ||
|
||
import com.austinv11.persistence.PreProcessor | ||
import java.security.MessageDigest | ||
import java.security.SecureRandom | ||
import java.util.concurrent.ConcurrentHashMap | ||
import javax.crypto.Cipher | ||
import javax.crypto.spec.SecretKeySpec | ||
|
||
internal const val KEY_LENGTH: Int = 16 | ||
internal const val SALT_LENGTH: Int = 32 | ||
|
||
/** | ||
* This encrypts data via a AES with the provided key. | ||
*/ | ||
class EncryptedPreProcessor(val key: String) : PreProcessor { | ||
|
||
private val secretKey = SecretKeySpec(MessageDigest.getInstance("SHA-1").digest(key.toByteArray()).copyOf(KEY_LENGTH), "AES") | ||
private val encryptionCipher | ||
get() = Cipher.getInstance("AES/ECB/PKCS5Padding").apply { this.init(Cipher.ENCRYPT_MODE, secretKey) } | ||
private val decryptionCipher | ||
get() = Cipher.getInstance("AES/ECB/PKCS5Padding").apply { this.init(Cipher.DECRYPT_MODE, secretKey) } | ||
private val connectionMetadata = ConcurrentHashMap<String, ConnectionMetadata>() | ||
|
||
override fun getKey(): Byte = 1 | ||
|
||
override fun pack(host: String, port: Int, input: ByteArray): ByteArray { | ||
if (!connectionMetadata.containsKey("host:$port")) { //If there isn't metadata on this end, this is a client since its the one to pack first | ||
connectionMetadata["host:$port"] = ConnectionMetadata(false) | ||
} | ||
|
||
val metadata = connectionMetadata["host:$port"]!! | ||
synchronized(metadata) { | ||
if (!metadata.didCompleteHandshake) { //No need to do special handling if the handshake is finished | ||
if (metadata.isServerSide) { //When this is server side, we are likely packing the OK payload (if not, who cares? its a failed connection) | ||
metadata.didCompleteHandshake = true //Mark completed handshake server side | ||
return ByteArray(SALT_LENGTH).apply { SecureRandom().nextBytes(this); metadata.salt = this } + input //Create a random salt and prepend it to the (raw) payload since there's no sensitive info yet | ||
} else { | ||
return input //This is the client side, so we don't have the salt yet, so no processing yet | ||
} | ||
} | ||
|
||
|
||
return encryptionCipher.doFinal(metadata.salt!! + input) //Normal operation, encrypt the input with the prepended salt | ||
} | ||
} | ||
|
||
override fun consume(host: String, port: Int, input: ByteArray): ByteArray { | ||
if (!connectionMetadata.containsKey("host:$port")) { //If there isn't metadata on this end, this is a server since its the one to consume first | ||
connectionMetadata["host:$port"] = ConnectionMetadata(true) | ||
} | ||
|
||
val metadata = connectionMetadata["host:$port"]!! | ||
synchronized(metadata) { | ||
if (!metadata.didCompleteHandshake) { //No need to do special handling if the handshake is finished | ||
if (!metadata.isServerSide) { //When client side, we must take the salt | ||
metadata.salt = input.copyOfRange(0, SALT_LENGTH) //Strip salt and store it | ||
metadata.didCompleteHandshake = true //Mark completed handshake client side | ||
return input.copyOfRange(SALT_LENGTH, input.size) //Strip the salt from the input and pass it forward (it still isn't encrypted at this point) | ||
} else { | ||
return input //When server side and we did not complete handshake, no need for processing since its unencrypted and has no salt yet | ||
} | ||
} | ||
|
||
return decryptionCipher.doFinal(input).copyOfRange(SALT_LENGTH, input.size) //Normal operation, decrypt the input and remove the salt | ||
} | ||
} | ||
|
||
data class ConnectionMetadata(@Volatile var isServerSide: Boolean, | ||
@Volatile var didCompleteHandshake: Boolean = false, | ||
@Volatile var salt: ByteArray? = null) | ||
} |
15 changes: 15 additions & 0 deletions
15
src/main/kotlin/com/austinv11/persistence/impl/NoOpPreProcessor.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package com.austinv11.persistence.impl | ||
|
||
import com.austinv11.persistence.PreProcessor | ||
|
||
/** | ||
* This does no pre processing to provided data. | ||
*/ | ||
class NoOpPreProcessor : PreProcessor { | ||
|
||
override fun getKey(): Byte = 0 | ||
|
||
override fun pack(host: String, port: Int, input: ByteArray): ByteArray = input | ||
|
||
override fun consume(host: String, port: Int, input: ByteArray): ByteArray = input | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.