Last active
May 12, 2023 16:51
-
-
Save sweis/ba80e826857c79fdfd16b882641983eb to your computer and use it in GitHub Desktop.
A decompiled class from the Twitter 9.88 APK -- Not original source
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
package p000; | |
import java.security.InvalidKeyException; | |
import java.security.PrivateKey; | |
import java.security.PublicKey; | |
import java.security.SecureRandom; | |
import org.bouncycastle.crypto.InvalidCipherTextException; | |
import org.bouncycastle.jcajce.provider.asymmetric.p445ec.KeyAgreementSpi; | |
import javax.crypto.Cipher; | |
/** | |
* This is decompiled from the Twitter 9.88.0-release.0 APK. This is NOT original source code. | |
* The variable names were manually filled in. | |
* | |
* The code uses Bouncy Castle and most of those classes are from here: https://github.com/bcgit/bc-java | |
*/ | |
public final class SessionKeyEncrypter { | |
public static ECNamedCurveParameterSpec secp256r1Spec() { | |
X9ECParameters x9ecParams = CustomNamedCurves.getByNameLazy("secp256r1").getParameters(); | |
return new ECNamedCurveParameterSpec( | |
"secp256r1", x9ecParams.curve, x9ecParams.getG(), | |
x9ecParams.n, x9ecParams.h, x9ecParams.getSeed() | |
); | |
} | |
public static byte[] generateSecret(PublicKey publicKey, PrivateKey privateKey) throws InvalidKeyException { | |
KeyAgreementSpi dh = new KeyAgreementSpi("ECDH", new ECDHBasicAgreement(), (DerivationFunction) null); | |
SecureRandom secureRandom = new SecureRandom(); | |
dh.engineInit(privateKey, secureRandom); | |
dh.engineDoPhase(publicKey, true); | |
return dh.engineGenerateSecret(); | |
} | |
public static byte[] encrypt(int opmode, byte[] key, byte[] nonce, byte[] message) | |
throws InvalidCipherTextException { | |
KeyParameter keyParam = new KeyParameter(key, 0, key.length); | |
GCMBlockCipher gcmCipher = new GCMBlockCipher(new AESEngine()); | |
AEADParameters aeadParams = new AEADParameters(keyParam, 128, nonce, null); | |
gcmCipher.init(opmode == Cipher.ENCRYPT_MODE, aeadParams); | |
byte[] output = new byte[gcmCipher.getOutputSize(message.length)]; | |
gcmCipher.doFinal(output, gcmCipher.processBytes(message, 0, message.length, output, 0)); | |
return output; | |
} | |
public static byte[] deriveKeyAndEncrypt(int opmode, byte[] sharedSecret, byte[] iv, byte[] message) | |
throws InvalidCipherTextException { | |
/* | |
* Source is: | |
* https://github.com/bcgit/bc-java/blob/master/prov/src/main/java/org/bouncycastle/jce/provider/BrokenKDF2BytesGenerator.java | |
* "Broken" means it was using an "implementation ... based on draft 9 of IEEE P1363a". The comments say | |
* "don't use it for anything that might be subject to long term storage." | |
*/ | |
BrokenKDF2BytesGenerator kdf = new BrokenKDF2BytesGenerator(new SHA256Digest()); | |
kdf.init(new KDFParameters(sharedSecret, iv)); | |
byte[] keyBytes = new byte[32]; | |
kdf.generateBytes(keyBytes, 0, 32); | |
byte[] key = ArrayUtils.sliceCopy(0, keyBytes, 16); | |
byte[] nonce = ArrayUtils.sliceCopy(16, keyBytes, 32); | |
return encrypt(opmode, key, nonce, message); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment