Search in sources :

Example 1 with BEncodedDictionary

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

the class Registration method parse.

static Registration parse(String data) {
    try {
        byte[] bytes = Base64.decode(data, Base64.NO_WRAP);
        BEncodedDictionary dict = BEncodedDictionary.parseDictionary(ByteBuffer.wrap(bytes));
        Registration ret = new Registration();
        ret.date = dict.getLong("date");
        ret.registrationId = dict.getString("registration_id");
        ret.endpoint = dict.getString("endpoint");
        ret.localSequenceNumber = dict.getInt("local_sequence_number");
        ret.remoteSequenceNumber = dict.getInt("remote_sequence_number");
        ret.state = dict.getInt("state");
        byte[] publicModulus = dict.getBytes("public_modulus");
        byte[] publicExponent = dict.getBytes("public_exponent");
        if (publicModulus != null && publicExponent != null) {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            RSAPublicKeySpec rsaPublicKeySpec = new RSAPublicKeySpec(new BigInteger(publicModulus), new BigInteger(publicExponent));
            ret.remotePublicKey = keyFactory.generatePublic(rsaPublicKeySpec);
        }
        return ret;
    } catch (Exception e) {
        return null;
    }
}
Also used : BigInteger(java.math.BigInteger) BEncodedDictionary(org.cyanogenmod.pushsms.bencode.BEncodedDictionary) RSAPublicKeySpec(java.security.spec.RSAPublicKeySpec) KeyFactory(java.security.KeyFactory)

Example 2 with BEncodedDictionary

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

the class GcmText method send.

public void send(GcmSocket gcmSocket, String id) {
    // serialize the message
    BEncodedDictionary message = new BEncodedDictionary();
    // mark the type as a message
    message.put("t", MessageTypes.MESSAGE);
    // grant an id to acknowledge
    message.put("id", id);
    message.put("sca", scAddr);
    BEncodedList texts = new BEncodedList();
    message.put("ts", texts);
    for (String text : this.texts) {
        texts.add(text);
    }
    gcmSocket.write(new ByteBufferList(message.toByteArray()));
}
Also used : ByteBufferList(com.koushikdutta.async.ByteBufferList) BEncodedDictionary(org.cyanogenmod.pushsms.bencode.BEncodedDictionary) BEncodedList(org.cyanogenmod.pushsms.bencode.BEncodedList)

Example 3 with BEncodedDictionary

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

the class MiddlewareService method parseGcmMessage.

private void parseGcmMessage(GcmSocket gcmSocket, ByteBufferList bb) {
    try {
        BEncodedDictionary message = BEncodedDictionary.parseDictionary(bb.getAllByteArray());
        String messageType = message.getString("t");
        if (MessageTypes.MESSAGE.equals(messageType)) {
            // incoming text via gcm
            GcmText gcmText = GcmText.parse(gcmSocket, message);
            if (gcmText == null)
                return;
            // ack the message
            String messageId = message.getString("id");
            if (messageId != null) {
                BEncodedDictionary ack = new BEncodedDictionary();
                ack.put("t", MessageTypes.ACK);
                ack.put("id", messageId);
                gcmSocket.write(new ByteBufferList(ack.toByteArray()));
            }
            // synthesize a fake message for the android system
            smsTransport.synthesizeMessages(gcmSocket.getNumber(), gcmText.scAddr, gcmText.texts, System.currentTimeMillis());
        } else if (MessageTypes.ACK.equals(messageType)) {
            // incoming ack
            String messageId = message.getString("id");
            if (messageId == null)
                return;
            GcmText gcmText = messagesAwaitingAck.remove(messageId);
            if (gcmText == null)
                return;
            firePendingIntents(gcmText.sentIntents);
            firePendingIntents(gcmText.deliveryIntents);
        }
    } catch (Exception e) {
        Log.e(LOGTAG, "Error handling GCM socket message", e);
    }
}
Also used : ByteBufferList(com.koushikdutta.async.ByteBufferList) BEncodedDictionary(org.cyanogenmod.pushsms.bencode.BEncodedDictionary) RemoteException(android.os.RemoteException) IOException(java.io.IOException)

Example 4 with BEncodedDictionary

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

the class Registration method encode.

public String encode() {
    try {
        BEncodedDictionary dict = new BEncodedDictionary();
        if (remotePublicKey != null) {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            RSAPublicKeySpec publicKeySpec = keyFactory.getKeySpec(remotePublicKey, RSAPublicKeySpec.class);
            dict.put("public_modulus", publicKeySpec.getModulus().toByteArray());
            dict.put("public_exponent", publicKeySpec.getPublicExponent().toByteArray());
        }
        dict.put("state", state);
        dict.put("date", date);
        dict.put("endpoint", endpoint);
        dict.put("registration_id", registrationId);
        dict.put("local_sequence_number", localSequenceNumber);
        dict.put("remote_sequence_number", remoteSequenceNumber);
        return Base64.encodeToString(dict.toByteArray(), Base64.NO_WRAP);
    } catch (Exception e) {
        return "";
    }
}
Also used : BEncodedDictionary(org.cyanogenmod.pushsms.bencode.BEncodedDictionary) RSAPublicKeySpec(java.security.spec.RSAPublicKeySpec) KeyFactory(java.security.KeyFactory)

Example 5 with BEncodedDictionary

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

the class GcmSocket method onGcmMessage.

public void onGcmMessage(String dataString, String from) {
    try {
        // base64 decode the payload that contains the encrypted symmetric key
        // and the corresponding encryptedSignedMessage
        BEncodedDictionary encryptedKeyMessagePair = BEncodedDictionary.parseDictionary(Base64.decode(dataString, Base64.NO_WRAP));
        BEncodedList encryptedSymmetricKeys = encryptedKeyMessagePair.getBEncodedList("esk");
        byte[] encryptedSignedMessage = encryptedKeyMessagePair.getBytes("esm");
        // to support multi recipient scenarios, the protocol sends an array
        // of encrypted symmetric keys. each key is encrypted once per intended recipient.
        // attempt to decode all of them, use the one that works.
        byte[] symmetricKey = null;
        for (int i = 0; i < encryptedSymmetricKeys.size(); i++) {
            try {
                byte[] encryptedSymmetricKey = encryptedSymmetricKeys.getBytes(i);
                // decrypt the symmetric key
                Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
                cipher.init(Cipher.DECRYPT_MODE, gcmConnectionManager.privateKey);
                symmetricKey = cipher.doFinal(encryptedSymmetricKey);
                break;
            } catch (Exception e) {
            }
        }
        if (symmetricKey == null)
            throw new Exception("could not decrypt symmetric key");
        // decrypt the message
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(symmetricKey, "AES"));
        BEncodedDictionary signedMessage = BEncodedDictionary.parseDictionary(cipher.doFinal(encryptedSignedMessage));
        // grab the signature and the signed data, and verify the sender authenticity
        byte[] signature = signedMessage.getBytes("s");
        byte[] signedEnvelope = signedMessage.getBytes("d");
        Signature verifier = Signature.getInstance("SHA1withRSA");
        verifier.initVerify(registration.remotePublicKey);
        verifier.update(signedEnvelope);
        if (!verifier.verify(signature)) {
            // keys or something changed? force a server refresh
            registration.refresh();
            throw new Exception("unable to verify signature");
        }
        originatingNumber = from;
        BEncodedDictionary envelope = BEncodedDictionary.parseDictionary(signedEnvelope);
        int seq = envelope.getInt("lsn");
        if (registration.remoteSequenceNumber <= seq) {
        // wtf? replay attack?
        // how to handle? Ignore? prompt?
        }
        registration.remoteSequenceNumber = seq;
        // the remote end will send us what they think our local sequence number is... just use
        // the max of the two
        registration.localSequenceNumber = Math.max(envelope.getInt("rsn"), registration.localSequenceNumber);
        Util.emitAllData(this, new ByteBufferList(envelope.getBytes("p")));
    } catch (Exception e) {
        Log.e(LOGTAG, "Parse exception", e);
    }
}
Also used : ByteBufferList(com.koushikdutta.async.ByteBufferList) SecretKeySpec(javax.crypto.spec.SecretKeySpec) Signature(java.security.Signature) BEncodedDictionary(org.cyanogenmod.pushsms.bencode.BEncodedDictionary) Cipher(javax.crypto.Cipher) BEncodedList(org.cyanogenmod.pushsms.bencode.BEncodedList)

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