Package se.despotify.client.protocol.channel

Source Code of se.despotify.client.protocol.channel.ChannelAudioHandler

package se.despotify.client.protocol.channel;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.io.OutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;

public class ChannelAudioHandler implements ChannelListener {
  private Cipher       cipher;
  private Key          key;
  private byte[]       iv;
  private int          offset;
  private OutputStream output;
 
  public ChannelAudioHandler(byte[] key, OutputStream output){
    /* Get AES cipher instance. */
    try {
      this.cipher = Cipher.getInstance("AES/CTR/NoPadding");
    }
    catch (NoSuchAlgorithmException e){
      System.err.println("AES not available! Aargh!");
    }
    catch (NoSuchPaddingException e){
      System.out.println("No padding not available... haha!");
    }
   
    /* Create secret key from bytes. */
    this.key = new SecretKeySpec(key, "AES");
   
    /* Set IV. */
    this.iv = new byte[]{
      (byte)0x72, (byte)0xe0, (byte)0x67, (byte)0xfb,
      (byte)0xdd, (byte)0xcb, (byte)0xcf, (byte)0x77,
      (byte)0xeb, (byte)0xe8, (byte)0xbc, (byte)0x64,
      (byte)0x3f, (byte)0x63, (byte)0x0d, (byte)0x93
    };
   
    /* Initialize cipher with key and iv in encrypt mode. */
    try {
      this.cipher.init(Cipher.ENCRYPT_MODE, this.key, new IvParameterSpec(this.iv));
    }
    catch (InvalidKeyException e){
      System.out.println("Invalid key!");
    }
    catch (InvalidAlgorithmParameterException e){
      System.out.println("Invalid IV!");
    }
   
    /* Set output stream. */
    this.output = output;
  }
 
  public void channelHeader(Channel channel, byte[] header){
    /* Do nothing. */
  }
 
  public void channelData(Channel channel, byte[] data){
    /* Offsets needed for deinterleaving. */
    int off, w, x, y, z;
   
    /* Allocate space for ciphertext. */
    byte[] ciphertext = new byte[data.length + 1024];
    byte[] keystream  = new byte[16];
   
    /* Decrypt each 1024 byte block. */
    for(int block = 0; block < data.length / 1024; block++){
      /* Deinterleave the 4x256 byte blocks. */
      off = block * 1024;
      w  = block * 1024 + 0 * 256;
      x  = block * 1024 + 1 * 256;
      y  = block * 1024 + 2 * 256;
      z  = block * 1024 + 3 * 256;
     
      for(int i = 0; i < 1024 && (block * 1024 + i) < data.length; i += 4){
        ciphertext[off++] = data[w++];
        ciphertext[off++] = data[x++];
        ciphertext[off++] = data[y++];
        ciphertext[off++] = data[z++];
      }
     
      /* Decrypt 1024 bytes block. This will fail for the last block. */
      for(int i = 0; i < 1024 && (block * 1024 + i) < data.length; i += 16){
        /* Produce 16 bytes of keystream from the IV. */
        try{
          keystream = this.cipher.doFinal(this.iv);
        }
        catch(IllegalBlockSizeException e){
          e.printStackTrace();
        }
        catch(BadPaddingException e){
          e.printStackTrace();
        }
       
        /*
         * Produce plaintext by XORing ciphertext with keystream.
         * And somehow I also need to XOR with the IV... Please
         * somebody tell me what I'm doing wrong, or is it the
         * Java implementation of AES? At least it works like this.
         */
        for(int j = 0; j < 16; j++){
          ciphertext[block * 1024 + i + j] ^= keystream[j] ^ this.iv[j];
        }

        /* Update IV counter. */
        for(int j = 15; j >= 0; j--){
          this.iv[j] += 1;
         
          if((int)(this.iv[j] & 0xFF) != 0){
            break;
          }
        }
       
        /* Set new IV. */
        try{
          this.cipher.init(Cipher.ENCRYPT_MODE, this.key, new IvParameterSpec(this.iv));
        }
        catch(InvalidKeyException e){
          e.printStackTrace();
        }
        catch(InvalidAlgorithmParameterException e){
          e.printStackTrace();
        }
      }
    }
   
    /* Write data to output stream. */
    try{
      this.output.write(ciphertext, 0, ciphertext.length - 1024);
    }
    catch(IOException e){
      /* Just don't care... */
    }
  }
 
  public void channelEnd(Channel channel){
    this.offset += channel.getDataLength();
   
    Channel.unregister(channel.getId());
  }
 
  public void channelError(Channel channel){
    /* Do nothing. */
  }
TOP

Related Classes of se.despotify.client.protocol.channel.ChannelAudioHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.