/// <summary> /// Request a part of the encrypted file from the server. /// /// The data should be decrypted using AES key in CTR mode /// with AES key provided and a static IV, incremented for /// each 16 byte data processed. /// </summary> public void SendSubstreamRequest(IChannelListener listener, Sharpotify.Media.File file, int offset, int length) { /* Create channel and buffer. */ Channel.Channel channel = new Channel.Channel("Substream-Channel", Channel.ChannelType.TYPE_SUBSTREAM, listener); ByteBuffer buffer = ByteBuffer.Allocate(2 + 2 + 2 + 2 + 2 + 2 + 2 + 4 + 20 + 4 + 4); /* Append channel id. */ buffer.PutShort((short)channel.Id); /* Unknown 10 bytes. */ buffer.PutShort((short)0x0800); buffer.PutShort((short)0x0000); buffer.PutShort((short)0x0000); buffer.PutShort((short)0x0000); buffer.PutShort((short)0x0000); buffer.PutShort((short)0x4e20); /* Unknown (static value) */ buffer.PutInt(200 * 1000); /* 20 bytes file id. */ buffer.Put(Hex.ToBytes(file.Id)); if (offset % 4096 != 0 || length % 4096 != 0 || length == 0) { throw new ArgumentException("Offset and length need to be a multiple of 4096."); } offset >>= 2; length >>= 2; /* Append offset and length. */ buffer.PutInt(offset); buffer.PutInt(offset + length); buffer.Flip(); /* Register channel. */ Channel.Channel.Register(channel); /* Send packet. */ this.SendPacket(Command.COMMAND_GETSUBSTREAM, buffer); }
/// <summary> /// Request AES key for a track. /// </summary> public void SendAesKeyRequest(IChannelListener listener, Track track, Sharpotify.Media.File file) { /* Create channel and buffer. */ Channel.Channel channel = new Channel.Channel("AES-Key-Channel", Channel.ChannelType.TYPE_AESKEY, listener); ByteBuffer buffer = ByteBuffer.Allocate(20 + 16 + 2 + 2 + 2); /* Request the AES key for this file by sending the file id and track id. */ buffer.Put(Hex.ToBytes(file.Id)); /* 20 bytes */ buffer.Put(Hex.ToBytes(track.Id)); /* 16 bytes */ buffer.PutShort((short)0x0000); buffer.PutShort((short)channel.Id); buffer.PutShort((short)0x0000); buffer.Flip(); /* Register channel. */ Channel.Channel.Register(channel); /* Send packet. */ this.SendPacket(Command.COMMAND_REQKEY, buffer); }