/// <summary> /// Returns document. /// </summary> /// <param name="stream">Stream.</param> /// <param name="password">Password.</param> /// <exception cref="FormatException">Cannot parse document.</exception> public static BimilDocument Open(Stream stream, string password) { try { using (var timer = new Medo.Diagnostics.LifetimeWatch("Open")) { var doc = new BimilDocument(); var salt = new byte[16]; stream.Read(salt, 0, 16); doc.PasswordSalt = salt; var deriveBytes = new Rfc2898DeriveBytes(UTF8Encoding.UTF8.GetBytes(password), doc.PasswordSalt, 4096); doc.Crypto.Key = deriveBytes.GetBytes(16); doc.Crypto.IV = deriveBytes.GetBytes(16); var encBuffer = new byte[stream.Length - 16]; stream.Read(encBuffer, 0, encBuffer.Length); byte[] decBuffer; using (var dec = doc.Crypto.CreateDecryptor()) { decBuffer = dec.TransformFinalBlock(encBuffer, 0, encBuffer.Length); } if ((decBuffer[0] == 0x41) && (decBuffer[1] == 0x31) && (decBuffer[2] == 0x32) && (decBuffer[3] == 0x38)) { if ((decBuffer[decBuffer.Length - 4] != 0x41) || (decBuffer[decBuffer.Length - 3] != 0x31) || (decBuffer[decBuffer.Length - 2] != 0x32) || (decBuffer[decBuffer.Length - 1] != 0x38)) { throw new FormatException("Invalid secondary identifier."); } doc.Id = "A128"; } else { throw new FormatException("Invalid primary identifier."); } var currOffset = 4; while (currOffset < (decBuffer.Length - 4)) { var itemLen = GetInt32(decBuffer, currOffset); var item = BimilItem.Parse(doc, decBuffer, currOffset + 4, itemLen); doc.Items.Add(item); currOffset += 4 + itemLen; } return(doc); } } catch (CryptographicException ex) { throw new FormatException("Cannot parse document.", ex); } catch (OverflowException ex) { throw new FormatException("Cannot parse document.", ex); } catch (SecurityException ex) { throw new FormatException("Cannot parse document.", ex); } }
/// <summary> /// Saves current document to stream. /// </summary> /// <param name="stream">Stream.</param> public void Save(Stream stream) { using (var timer = new Medo.Diagnostics.LifetimeWatch("Save")) { stream.Write(this.PasswordSalt, 0, this.PasswordSalt.Length); var buffer = new List <byte>(65536); buffer.AddRange(new byte[] { 0x41, 0x31, 0x32, 0x38 }); foreach (var item in this.Items) { var bytes = item.GetBytes(); buffer.AddRange(GetInt32Bytes(bytes.Length)); buffer.AddRange(bytes); } buffer.AddRange(new byte[] { 0x41, 0x31, 0x32, 0x38 }); byte[] encBuffer; using (var enc = this.Crypto.CreateEncryptor()) { encBuffer = enc.TransformFinalBlock(buffer.ToArray(), 0, buffer.Count); } stream.Write(encBuffer, 0, encBuffer.Length); } }