Search in sources :

Example 6 with BEncodedDictionary

use of org.cyanogenmod.pushsms.bencode.BEncodedDictionary in project PushSms by koush.

the class GcmSocket method write.

@Override
public void write(ByteBufferList bb) {
    try {
        assert registration != null;
        // construct a gcm json post object
        JsonObject post = new JsonObject();
        JsonArray regs = new JsonArray();
        regs.add(new JsonPrimitive(registration.registrationId));
        post.add("registration_ids", regs);
        JsonObject data = new JsonObject();
        post.add("data", data);
        // serialize the unencrypted message
        BEncodedDictionary envelope = new BEncodedDictionary();
        // plop in the data we want to deliver
        envelope.put("p", bb.getAllByteArray());
        // include a sequence number to prevent replay attacks
        envelope.put("lsn", registration.localSequenceNumber++);
        // let the other end know what their sequence number is
        // just in case we're out of sync
        envelope.put("rsn", registration.remoteSequenceNumber);
        // sign the data so authenticity can be verified
        BEncodedDictionary signedMessage = new BEncodedDictionary();
        byte[] signedEnvelope = envelope.toByteArray();
        Signature signer = Signature.getInstance("SHA1withRSA");
        signer.initSign(gcmConnectionManager.privateKey);
        signer.update(signedEnvelope);
        byte[] signature = signer.sign();
        signedMessage.put("d", signedEnvelope);
        signedMessage.put("s", signature);
        // generate a symmetric key to be encrypted by the remote public key,
        // and encrypt that. Asymmetric keys have payload limitations.
        // http://en.wikipedia.org/wiki/Hybrid_cryptosystem
        // http://stackoverflow.com/questions/6788018/android-encryption-decryption-with-aes
        // see also the added benefit of multi recipient scenarios:
        // http://security.stackexchange.com/questions/20134/in-pgp-why-not-just-encrypt-message-with-recipients-public-key-why-the-meta-e/20145#20145
        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        SecureRandom secureRandom = new SecureRandom();
        keyGenerator.init(128, secureRandom);
        byte[] symmetricKey = keyGenerator.generateKey().getEncoded();
        // Signature AND message should both be encrypted, as much as possible should be opaque:
        // http://stackoverflow.com/questions/6587023/should-i-encrypt-the-signature
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(symmetricKey, "AES"));
        byte[] encryptedSignedMessage = cipher.doFinal(signedMessage.toByteArray());
        // Encrypt the asymmetric key so only the remote can decrypt it, and
        // thus decrypt the message payload
        cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, registration.remotePublicKey);
        byte[] encryptedSymmetricKey = cipher.doFinal(symmetricKey);
        // put the encrypted symmetric key and encrypted payload into the JSON, and send it off
        BEncodedDictionary payload = new BEncodedDictionary();
        // though right now we only put in a single encrypted symmetric key,
        // wrap that key in an array. this will future proof the protocol
        // for later possible multi recipient scenarios.
        BEncodedList encryptedSymmetricKeys = new BEncodedList();
        encryptedSymmetricKeys.add(encryptedSymmetricKey);
        payload.put("esk", encryptedSymmetricKeys);
        payload.put("esm", encryptedSignedMessage);
        // now base64 the entire encrypted payload
        data.add("p", new JsonPrimitive(Base64.encodeToString(payload.toByteArray(), Base64.NO_WRAP)));
        // include our claimed number, as we would a text, so the other end can find us
        data.addProperty("f", gcmConnectionManager.from);
        // ship it
        Ion.with(context).load("https://android.googleapis.com/gcm/send").setHeader("Authorization", "key=" + gcmConnectionManager.gcmApiKey).setJsonObjectBody(post).as(GcmResults.class).setCallback(new FutureCallback<GcmResults>() {

            @Override
            public void onCompleted(Exception e, GcmResults result) {
                if (result == null || result.failure != 0 || result.success == 0) {
                    if (e == null) {
                        e = new Exception("gcm server failure");
                        // to trigger a refresh
                        if (registration.isRegistered())
                            registration.unregister();
                    }
                    report(e);
                    return;
                }
                currentBackoff = GRACE_DEFAULT;
            }
        });
    } catch (Exception e) {
        Log.e(LOGTAG, "Send exception", e);
        report(e);
    }
}
Also used : JsonPrimitive(com.google.gson.JsonPrimitive) JsonObject(com.google.gson.JsonObject) SecureRandom(java.security.SecureRandom) BEncodedDictionary(org.cyanogenmod.pushsms.bencode.BEncodedDictionary) BEncodedList(org.cyanogenmod.pushsms.bencode.BEncodedList) JsonArray(com.google.gson.JsonArray) SecretKeySpec(javax.crypto.spec.SecretKeySpec) Signature(java.security.Signature) Cipher(javax.crypto.Cipher) KeyGenerator(javax.crypto.KeyGenerator)

Example 7 with BEncodedDictionary

use of org.cyanogenmod.pushsms.bencode.BEncodedDictionary in project PushSms by koush.

the class SmsSocket method write.

@Override
public void write(ByteBufferList bb) {
    final int thisMessageId = messageId++;
    int parts = (bb.remaining() / 100) + 1;
    int i = 0;
    while (bb.hasRemaining()) {
        BEncodedDictionary dict = new BEncodedDictionary();
        dict.put("m", thisMessageId);
        dict.put("c", parts);
        dict.put("i", i++);
        byte[] bytes = new byte[Math.min(bb.remaining(), 100)];
        bb.get(bytes);
        dict.put("d", bytes);
        SmsManager.getDefault().sendDataMessage(number, null, smsPort, dict.toByteArray(), null, null);
    }
}
Also used : BEncodedDictionary(org.cyanogenmod.pushsms.bencode.BEncodedDictionary)

Aggregations

BEncodedDictionary (org.cyanogenmod.pushsms.bencode.BEncodedDictionary)7 ByteBufferList (com.koushikdutta.async.ByteBufferList)3 BEncodedList (org.cyanogenmod.pushsms.bencode.BEncodedList)3 KeyFactory (java.security.KeyFactory)2 Signature (java.security.Signature)2 RSAPublicKeySpec (java.security.spec.RSAPublicKeySpec)2 Cipher (javax.crypto.Cipher)2 SecretKeySpec (javax.crypto.spec.SecretKeySpec)2 RemoteException (android.os.RemoteException)1 JsonArray (com.google.gson.JsonArray)1 JsonObject (com.google.gson.JsonObject)1 JsonPrimitive (com.google.gson.JsonPrimitive)1 IOException (java.io.IOException)1 BigInteger (java.math.BigInteger)1 SecureRandom (java.security.SecureRandom)1 KeyGenerator (javax.crypto.KeyGenerator)1