2010-03-02 4 views
3

Je dois crypter et envoyer des données sur TCP (de quelques 100 octets à quelques 100 mégaoctets par message) dans les blocs de Java vers un programme C++, et j'ai besoin d'envoyer la taille des données à l'avance afin que le le destinataire sait quand arrêter la lecture du message courant et le traiter, puis attendre le message suivant (la connexion reste ouverte donc il n'y a pas d'autre moyen d'indiquer la fin du message, comme les données peuvent être binaires, je ne peux pas utiliser un drapeau indiquer la fin du message en raison de la possibilité que les octets cryptés soient aléatoirement identiques à n'importe quel drapeau que je choisis à un moment donné).Constante getOutputSize?

Ma question calcule la taille du message crypté avant de le chiffrer, qui sera en général différente de la longueur d'entrée en raison de rembourrage, etc.

Dire que j'ai initialisé comme suit:

AlgorithmParameterSpec paramSpec = new IvParameterSpec(initv); 
encipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
mac = Mac.getInstance("HmacSHA512"); 
encipher.init(Cipher.ENCRYPT_MODE, key, paramSpec); 
mac.init(key); 
buf = new byte[encipher.getOutputSize(blockSize)]; 

Ensuite, J'envoie les données en tant que tel (et aussi avoir une fonction analogue qui utilise un courant pour l'entrée à la place de byte[]):

public void writeBytes(DataOutputStream out, byte[] input) { 
try { 
    //mac.reset(); // Needed ? 
    int left = input.length; 
    int offset = 0; 
    while (left > 0) 
    { 
    int chunk = Math.min(left, blockSize); 
    int ctLength = encipher.update(input, offset, chunk, buf, 0); 
    mac.update(input, offset, chunk); 
    out.write(buf, 0, ctLength); 
    left -= chunk; 
    offset += chunk; 
    } 
    out.write(encipher.doFinal(mac.doFinal()); 
    out.flush(); 
} catch (Exception e) { 
    e.printStackTrace(); 
} 
} 

Mais comment précalculer la taille de sortie qui sera envoyée à l'ordinateur récepteur? Fondamentalement, je veux out.writeInt (messageSize) avant la boucle. Mais comment calculer messageSize? La documentation de getOutputSize() de Cipher indique que "Cet appel prend en compte toutes les données non traitées (mises en mémoire tampon) d'un précédent appel de mise à jour et le remplissage". Donc, cela semble impliquer que la valeur peut changer pour le même argument de fonction sur plusieurs appels à update() ou doFinal() ... Puis-je supposer que si blockSize est un multiple de la taille de bloc CBC AES pour éviter le rembourrage, je devrais avoir une valeur constante pour chaque bloc? Autrement dit, vérifiez simplement que _blockSize % encipher.getOutputSize(1) != 0 puis dans la fonction d'écriture,

int messageSize = (input.length/blockSize) * encipher.getOutputSize(blockSize) +      
        encipher.getOutputSize(input.length % blockSize + mac.getMacLength()); 

??

Sinon, quelles sont mes alternatives?

+1

Votre juste deviner, patcher, prier. Utilisez SSL/TLS. Java JSSE a un support facile à utiliser pour SSL. –

+0

Greg, je ne peux pas faire cela parce que le système doit être symétrique, clé privée seulement - authentification par clé publique/échange de clés. L'implémentation Java actuelle ne supporte pas cela. – Prune

Répondre

1

Lorsque vous utilisez un rembourrage PKCS5, la taille du message après padding sera:

padded_size = original_size + BLOCKSIZE - (original_size % BLOCKSIZE); 

qui précède donne la taille totale du message entier (jusqu'à l'appel doFinal()), compte tenu de la complète taille du message d'entrée. Il me vient à l'esprit que vous voulez simplement connaître la longueur de la dernière partie - tout ce que vous devez faire est de stocker le tableau d'octets de sortie de l'appel doFinal(), et d'utiliser la méthode .length() sur ce tableau.

+0

Salut caf, je suppose BLOCKSIZE est ce que renvoie Cipher.getBlocksize()? Merci – Prune

+0

Oui (cela devrait être 16 pour AES). – caf