public string ComputeChecksumAsync(IComputeChecksumCallback callback) { if (isDir_) { checksum_ = ""; } else { FileStream fstr = null; try { fstr = new FileStream(name_, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); MD5CryptoServiceProvider md5er = new MD5CryptoServiceProvider(); int bufsize = 64 * 1024; //64K Buffer byte[] buf = new byte[bufsize]; long curpos = 0; while (true) { int readCount = fstr.Read(buf, 0, bufsize); if (readCount < bufsize) { md5er.TransformFinalBlock(buf, 0, readCount); curpos = size_; break; } else { md5er.TransformBlock(buf, 0, readCount, buf, 0); curpos += readCount; } if (callback != null) { if (!callback.RaiseCallback(curpos, size_)) { throw new Exception("Checksum computation will be aborted by user."); } } } StringBuilder md5str = new StringBuilder(); foreach (byte b in md5er.Hash) { md5str.AppendFormat("{0:X2}", b); } checksum_ = md5str.ToString(); } catch (Exception ex) { return(ex.Message); } finally { if (fstr != null) { fstr.Close(); } } } return(null); }
private string ComputeValidator( string strURL, string strUserAgent ) { string strRandom = String.Format( "{0:X8}", new Random().Next() ); byte [] abRandom = Encoding.ASCII.GetBytes( strRandom ); byte [] abStatic = Convert.FromBase64String( "ROkjAaKid4EUF5kGtTNn3Q==" ); int p = 0; for( int i = 0; i < 3 && p != -1; i++ ) p = strURL.IndexOf( '/', p + 1 ); byte [] abURL = Encoding.ASCII.GetBytes( strURL.Substring( p ) ); byte [] abUA = Encoding.ASCII.GetBytes( strUserAgent ); MD5CryptoServiceProvider MD5 = new MD5CryptoServiceProvider(); MD5.TransformBlock( abURL, 0, abURL.Length, abURL, 0 ); MD5.TransformBlock( abUA, 0, abUA.Length, abUA, 0 ); MD5.TransformBlock( abStatic, 0, abStatic.Length, abStatic, 0 ); MD5.TransformFinalBlock( abRandom, 0, abRandom.Length ); return String.Format( "{0}-{1}", strRandom, BitConverter.ToString( MD5.Hash ).Replace( "-", "" ) ); }
/// <summary> /// The main processor -- convert a decrypted atom tree to an encrypted one. See in-line comments. /// </summary> /// <returns>true if the operation was successful</returns> public bool Process() { // Get the position of mdat before changes -- this will be necessary for chunk table offseting long positionBefore = _root.Child("mdat").Position; // Find the mp4a atom -- if not found, we're given a wrong file Atoms mp4a = _root.Child("moov").Child("trak").Child("mdia").Child("minf").Child("stbl").Child("stsd").Child("mp4a"); if (mp4a == null || _outfile == null) { return(false); } Atoms sinf = mp4a.AppendAtom("sinf", null); // Append an atom to sinf, containing the data "mp4a" byte[] frma = Encoding.ASCII.GetBytes("mp4a"); sinf.AppendAtom("frma", frma); // Append an atom to sinf, containing the data "itun" and 8 NULLs. Then append the schi atom to sinf byte[] schm = new byte[12]; schm.Initialize(); Encoding.ASCII.GetBytes("itun", 0, 4, schm, 4); sinf.AppendAtom("schm", schm); Atoms schi = sinf.AppendAtom("schi", null); // Grab the private key from the configuration file byte[] privateKey = Utility.ToByteArray(ConfigurationSettings.AppSettings["privateKey"]); // Append the user atom to schi schi.AppendAtom("user", Utility.ToByteArray(ConfigurationSettings.AppSettings["user"])); // Grab the key from the configuration file (obtained using iTunes' server) and append to schi byte[] keyData = BitConverter.GetBytes(Convert.ToInt32(ConfigurationSettings.AppSettings["key"])); Utility.Reverse(keyData); schi.AppendAtom("key ", keyData); // Grab the iviv and append to schi byte[] ivivData = Utility.ToByteArray(ConfigurationSettings.AppSettings["iviv"]); schi.AppendAtom("iviv", ivivData); // Grab the righ and append to schi byte[] righData = Utility.ToByteArray(ConfigurationSettings.AppSettings["righ"], 80); schi.AppendAtom("righ", righData); // Append the name atom (with the user's name, followed by NULLs) to schi byte[] nameData = new byte[256]; Encoding.ASCII.GetBytes(ConfigurationSettings.AppSettings["name"]).CopyTo(nameData, 0); string nameString = Encoding.ASCII.GetString(nameData); schi.AppendAtom("name", nameData); // Append the priv data to schi, and encrypt it byte[] privData = Utility.ToByteArray(ConfigurationSettings.AppSettings["priv"], 440); schi.AppendAtom("priv", privData); byte[] privDataEncrypted = new byte[440]; privData.CopyTo(privDataEncrypted, 0); // Hash the name and the iviv MD5CryptoServiceProvider MD5 = new MD5CryptoServiceProvider(); byte[] nameHashed = new byte[16]; MD5.TransformBlock(nameData, 0, nameString.IndexOf('\0'), nameHashed, 0); MD5.TransformFinalBlock(ivivData, 0, ivivData.Length); // Perform the encryption of the hash to get the new key and iv Utility.RijndaelCrypt(privData, 0, privData.Length, privateKey, MD5.Hash, false); if (Encoding.ASCII.GetString(privData, 0, 4) != "itun") { throw new Exception("The priv atom, the privateKey, or the name and iviv fields are invalid"); } byte[] mdatKey = new byte[16]; Array.Copy(privData, 24, mdatKey, 0, 16); byte[] mdatIV = new byte[16]; Array.Copy(privData, 48, mdatIV, 0, 16); // Get the sample table Atoms stbl = _root.Child("moov").Child("trak").Child("mdia").Child("minf").Child("stbl"); Atoms stsz = stbl.Child("stsz"); GetSampleTable(stsz.Data); byte[] mdatData = _root.Child("mdat").Data; int offset = 0; // Encrypt all the chunks using the new key and iviv for (int i = 0; i < _table.Length; ++i) { Utility.RijndaelCrypt(mdatData, offset, (int)_table[i], mdatKey, mdatIV, true); offset += (int)_table[i]; } // Change the type from m4pa to drms. Update chunk sizes (since we've appended quite a lot!) mp4a.Type = "drms"; _root.GetAndUpdateSize(); // Update the chunk table (since the offsets shifted) long positionAfter = _root.Child("mdat").Position; Atoms stco = stbl.Child("stco"); UpdateChunkTable(stco.Data, (int)(positionAfter - positionBefore)); // Write the resulting data to the output file byte[] data = _root.Bytes; _output.Write(data, 0, data.Length); return(true); }