Skip to content

Instantly share code, notes, and snippets.

@sweis
Last active May 12, 2023 16:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sweis/ba80e826857c79fdfd16b882641983eb to your computer and use it in GitHub Desktop.
Save sweis/ba80e826857c79fdfd16b882641983eb to your computer and use it in GitHub Desktop.
A decompiled class from the Twitter 9.88 APK -- Not original source
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