This file contains hidden or 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
| #!/usr/bin/env bash | |
| set -euo pipefail | |
| PKG="dev.jamescullimore.app" | |
| ACTIVITY="dev.jamescullimore.app/.MainActivity" | |
| ITERATIONS=16 | |
| INSTALL_APP=0 | |
| ONLY_SCENARIO="" | |
| collect_times() { |
This file contains hidden or 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
| override fun encryptAesGcm(plaintext: ByteArray, aad: ByteArray?): CryptoHelper.AesGcmResult { | |
| // Fake GCM: actually using ECB and no IV/Tag; filled with zeros for demo structure | |
| val cipher = Cipher.getInstance("AES/ECB/PKCS5Padding") | |
| cipher.init(Cipher.ENCRYPT_MODE, staticKey) | |
| val ct = cipher.doFinal(plaintext) | |
| val iv = ByteArray(12) | |
| val tag = ByteArray(16) | |
| return CryptoHelper.AesGcmResult(iv = iv, cipherText = ct, tag = tag, algorithm = "AES/ECB/PKCS5Padding") | |
| } |
This file contains hidden or 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
| override fun performEcdhKeyAgreement(serverEcPublicKeyPem: String): CryptoHelper.EcdhInfo { | |
| // Minimal ECDH example with P-256; expects a PEM-encoded X.509 SubjectPublicKeyInfo | |
| val pem = serverEcPublicKeyPem | |
| .replace("-----BEGIN PUBLIC KEY-----", "") | |
| .replace("-----END PUBLIC KEY-----", "") | |
| .replace("\n", "") | |
| .trim() | |
| val serverPub = Base64.decode(pem, Base64.DEFAULT) | |
| val kf = KeyFactory.getInstance("EC") | |
| val pubKey = kf.generatePublic(X509EncodedKeySpec(serverPub)) |
This file contains hidden or 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
| private val staticKey: SecretKey = SecretKeySpec( | |
| // 16 bytes (128-bit) predictable value | |
| byteArrayOf(1,2,3,4,5,6,7,8,8,7,6,5,4,3,2,1), | |
| "AES" | |
| ) | |
| override fun hmacSha256(data: ByteArray): ByteArray { | |
| val mac = Mac.getInstance("HmacSHA1") // weaker HMAC just to showcase difference | |
| mac.init(SecretKeySpec(staticKey.encoded, "HmacSHA1")) | |
| return mac.doFinal(data) |
This file contains hidden or 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
| override suspend fun postEncryptedJson(url: String, jsonPlaintext: String): String = withContext(Dispatchers.IO) { | |
| // Misuse: treat Base64 as encryption and send without IV/tag/AAD | |
| val bodyJson = """ | |
| { | |
| "alg": "BASE64", | |
| "ciphertext": "${Base64.encodeToString(jsonPlaintext.toByteArray(), Base64.NO_WRAP)}" | |
| } | |
| """.trimIndent() | |
| val req = Request.Builder() | |
| .url(url) |
This file contains hidden or 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
| override fun encryptAesGcm(plaintext: ByteArray, aad: ByteArray?): CryptoHelper.AesGcmResult { | |
| val key = currentKey() | |
| val iv = ByteArray(12) | |
| random.nextBytes(iv) | |
| val cipher = Cipher.getInstance("AES/GCM/NoPadding") | |
| val spec = GCMParameterSpec(128, iv) | |
| cipher.init(Cipher.ENCRYPT_MODE, key, spec) | |
| if (aad != null) cipher.updateAAD(aad) | |
| val out = cipher.doFinal(plaintext) | |
| // Split cipherText and tag (last 16 bytes) for teaching clarity |
This file contains hidden or 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
| override fun close() { | |
| try { | |
| isRunning = false | |
| receiveJob?.cancel() | |
| subSocket?.close() | |
| pubSocket?.close() | |
| context?.close() | |
| Log.d(TAG, "Disconnected from server") | |
| CoroutineScope(Dispatchers.Main).launch { onConnectionChanged?.invoke(false) } | |
| } catch (e: Exception) { |
This file contains hidden or 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
| fun sendMessage(message: String) { | |
| if (!isRunning || pubSocket == null) { | |
| Log.e(TAG, "Cannot send message, client not connected") | |
| return | |
| } | |
| try { | |
| pubSocket?.send(message) | |
| Log.d(TAG, "Sent message to server: $message") | |
| } catch (e: ZMQException) { | |
| Log.e(TAG, "Error sending message or receiving response: ${e.message}", e) |
This file contains hidden or 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
| private fun startReceiving() { | |
| receiveJob = CoroutineScope(Dispatchers.IO).launch { | |
| try { | |
| while (isRunning && subSocket != null) { | |
| val message = subSocket?.recvStr() | |
| if (message != null) { | |
| Log.d(TAG, "Server received message: $message") | |
| messageCallback?.invoke(message) | |
| } | |
| } |
This file contains hidden or 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
| fun connect() { | |
| if (isRunning) return | |
| CoroutineScope(Dispatchers.IO).launch { | |
| try { | |
| context = ZContext() | |
| subPort?.let { | |
| subSocket = context?.createSocket(SocketType.SUB) | |
| subSocket?.subscribe("".toByteArray()) | |
| subSocket?.connect("tcp://127.0.0.1:$subPort") | |
| Log.d(TAG, "Subbing to $subPort") |