internal static Stream Decrypt(Stream aStream, TEncryptionData Encryption) { using (TOle2File DataStream = new TOle2File(aStream, false)) { DataStream.SelectStream(XlsxConsts.EncryptionInfoString); byte[] RecordHeader = new byte[4 * 2]; DataStream.Read(RecordHeader, RecordHeader.Length); int vMajor = BitOps.GetWord(RecordHeader, 0); int vMinor = BitOps.GetWord(RecordHeader, 2); if ((vMajor == 0x03 || vMajor == 0x04) && vMinor == 0x02) { long Flags = BitOps.GetCardinal(RecordHeader, 4); if (Flags == 0x10) { XlsMessages.ThrowException(XlsErr.ErrNotSupportedEncryption); //external encryption } return(ReadStandardEncryptionInfo(DataStream, Encryption)); } else if (vMajor == 4 && vMinor == 4 && BitOps.GetCardinal(RecordHeader, 4) == 0x040) { return(ReadAgileEncryptionInfo(DataStream, Encryption)); } XlsMessages.ThrowException(XlsErr.ErrNotSupportedEncryption); return(null); } }
private static object[] GetNameDictionary(TOle2File Ole2File) { byte[] PropCountArray = new byte[4]; Ole2File.Read(PropCountArray, PropCountArray.Length); Int32 PropCount = BitOps.GetInt32(PropCountArray, 0); object[] Properties = new object[PropCount]; for (int i = 0; i < Properties.Length; i++) { TUnconvertedOlePropertyName PropName = new TUnconvertedOlePropertyName(); Ole2File.Read(PropCountArray, PropCountArray.Length); PropName.Id = BitConverter.ToUInt32(PropCountArray, 0); Ole2File.Read(PropCountArray, PropCountArray.Length); int StrLen = BitOps.GetInt32(PropCountArray, 0); if (StrLen <= 1) { PropName.Name = new TUnconvertedString(new byte[0], false); //StrLen includes the trailing #0 } else { byte[] Str = new byte[StrLen - 1]; Ole2File.Read(Str, Str.Length); Ole2File.SeekForward(Ole2File.Position + 1); //go over the 0 byte. This is needed for vectors/arrays. PropName.Name = new TUnconvertedString(Str, false); } Properties[i] = PropName; } return(Properties); }
private static Stream DecryptStream(TOle2File DataStream, TEncryptionParameters EncParams, TEncryptionKey Key) { DataStream.SelectStream(XlsxConsts.ContentString); byte[] EncryptedSize = new byte[8]; DataStream.Read(EncryptedSize, EncryptedSize.Length); AesManaged Engine = null; ICryptoTransform Decryptor = null; try { Engine = TEncryptionUtils.CreateEngine(EncParams); if (!Key.VariableIV) { Decryptor = Engine.CreateDecryptor(Key.Key, Key.IV); } return(new TXlsxCryptoStreamReader(DataStream, BitOps.GetCardinal(EncryptedSize, 0), Engine, Decryptor, Key)); } catch { if (Engine != null) { ((IDisposable)Engine).Dispose(); } if (Decryptor != null) { Decryptor.Dispose(); } throw; } }
private void FinishEncryption() { TEncryptionParameters EncParams = GetEncryptionParams(Protection); AesManaged EncEngine = TEncryptionUtils.CreateEngine(EncParams); TAgileEncryptionKey DataKey = TAgileEncryptionKey.CreateForWriting(null, EncEngine.KeySize / 8); DataKey.Key = TEncryptionUtils.GetRandom(DataKey.KeySizeInBytes); TAgileEncryptionKey KeyKey = TAgileEncryptionKey.CreateForWriting(Protection.OpenPassword, EncEngine.KeySize / 8); byte[] WorkLen = new byte[8]; BitOps.SetCardinal(WorkLen, 0, WorkingStream.Length - WorkStreamZeroPos); EncryptStream(EncEngine, DataKey, WorkLen); using (MemoryStream ms = new MemoryStream()) { using (TOle2File Ole2File = new TOle2File(GetEmptyEncryptedFile())) { Ole2File.PrepareForWrite(ms, XlsxConsts.EncryptionInfoString, new string[0]); CreateInfoStream(Ole2File, EncEngine, EncParams, KeyKey, DataKey); } ms.Position = 0; using (TOle2File Ole2File = new TOle2File(ms)) { Ole2File.PrepareForWrite(TargetStream, XlsxConsts.ContentString, new string[0]); WorkingStream.Position = 0; TEncryptionUtils.CopyStream(WorkingStream, Ole2File); } } }
internal TXlsRecordLoader(TOle2File aDataStream, TBiff8XFMap aXFMap, TSST aSST, IFlexCelFontList aFontList, TBorderList aBorderList, TPatternList aPatternList, TEncryptionData aEncryption, TXlsBiffVersion aXlsBiffVersion, TNameRecordList aNames, TVirtualReader VirtualReader) : base(aSST, aFontList, aEncryption, aXlsBiffVersion, aXFMap, aNames, VirtualReader) { DataStream = aDataStream; BorderList = aBorderList; PatternList = aPatternList; }
internal void Load(TOle2File OleFile) { PropertyList.Clear(); CheckHeader(OleFile); ReadPropHeader(OleFile); ReadPropSectionHeader(OleFile); }
public TXlsxCryptoStreamReader(TOle2File aDataStream, long aStreamLen, AesManaged aEncEncgine, ICryptoTransform aDecryptor, TEncryptionKey aKey) { DataStream = aDataStream; FStreamLen = aStreamLen; EncEngine = aEncEncgine; Decryptor = aDecryptor; CurrentSegment = new byte[SegmentSize]; Key = aKey; }
internal void WriteHeader(TOle2File OleFile) { OleFile.WriteRaw(PropHeader, PropHeader.Length); int SectCount = (int)BitOps.GetCardinal(PropHeader, 24); for (int i = 0; i < SectCount; i++) { OleFile.WriteRaw(FmtSection[i], FmtSection[i].Length); } }
internal static void CopyStream(Stream SourceStream, TOle2File DataStream) { byte[] buffer = new byte[8192]; int read; while ((read = SourceStream.Read(buffer, 0, buffer.Length)) > 0) { DataStream.Write(buffer, 0, read); } }
private void ReadPropHeader(TOle2File OleFile) { int SectCount = (int)BitOps.GetCardinal(PropHeader, 24); FmtSection = new byte[SectCount][]; for (int i = 0; i < SectCount; i++) { FmtSection[i] = new byte[16 + 4]; OleFile.Read(FmtSection[i], FmtSection[i].Length); } long SectorOffset = BitOps.GetCardinal(FmtSection[0], 16); OleFile.SeekForward(SectorOffset); }
private void CreateInfoStream(TOle2File DataStream, AesManaged EncEngine, TEncryptionParameters EncParams, TAgileEncryptionKey KeyKey, TAgileEncryptionKey DataKey) { DataStream.Write16(0x0004); DataStream.Write16(0x0004); DataStream.Write32(0x00040); byte[] InfoStreamXml = GetInfoStreamXml(EncEngine, EncParams, KeyKey, DataKey); DataStream.Write(InfoStreamXml, InfoStreamXml.Length); byte[] pad = new byte[4098 - InfoStreamXml.Length]; //Our Ole2 implementation will fill a sector with 0 so it doesn't go to the ministream. Those 0 will confuse Excel, so we will write spaces. for (int i = 0; i < pad.Length; i++) { pad[i] = 32; } DataStream.Write(pad, pad.Length); }
private void CheckHeader(TOle2File OleFile) { PropHeader = new byte[2 + 2 + 4 + 16 + 4]; OleFile.Read(PropHeader, PropHeader.Length); byte[] ExpectedHeader = { 0xFE, 0xFF, 0x00, 0x00 }; for (int i = 0; i < ExpectedHeader.Length; i++) { if (ExpectedHeader[i] != PropHeader[i]) { XlsMessages.ThrowException(XlsErr.ErrInvalidPropertySector); } } if (BitOps.GetCardinal(PropHeader, 24) < 1) //There should be at least one property section. { XlsMessages.ThrowException(XlsErr.ErrInvalidPropertySector); } }
private static Stream ReadAgileEncryptionInfo(TOle2File DataStream, TEncryptionData Encryption) { byte[] Enc = new byte[DataStream.Length - DataStream.Position]; DataStream.Read(Enc, Enc.Length); TEncryptionParameters DataEncParams = new TEncryptionParameters(); TAgileEncryptionKey DataKey = new TAgileEncryptionKey(); TAgileEncryptionVerifier KeyVerifier = new TAgileEncryptionVerifier(); TEncryptionParameters KeyEncParams = new TEncryptionParameters(); TAgileEncryptionKey KeyKey = new TAgileEncryptionKey(); using (MemoryStream ms = new MemoryStream(Enc)) { using (XmlReader xml = XmlReader.Create(ms)) { xml.ReadStartElement("encryption"); //goes to keyData ReadAgileCipherParams(xml, DataEncParams, DataKey); xml.ReadStartElement("keyData"); //goes to dataIntegrity //We are not checking data integrity at the moment. //DataIntegrity.EncryptedHMacKey = Convert.FromBase64String(xml.GetAttribute("encryptedHmacKey")); //DataIntegrity.EncryptedHmacValue = Convert.FromBase64String(xml.GetAttribute("encryptedHmacValue")); xml.ReadStartElement("dataIntegrity"); //goes to keyEncryptors xml.ReadStartElement("keyEncryptors"); //goes to keyEncryptor xml.ReadStartElement("keyEncryptor"); //goes to encryptedKey KeyKey.SpinCount = Convert.ToInt32(xml.GetAttribute("spinCount"), CultureInfo.InvariantCulture); ReadAgileCipherParams(xml, KeyEncParams, KeyKey); KeyVerifier.EncryptedVerifierHashInput = Convert.FromBase64String(xml.GetAttribute("encryptedVerifierHashInput")); KeyVerifier.EncryptedVerifierHashValue = Convert.FromBase64String(xml.GetAttribute("encryptedVerifierHashValue")); KeyVerifier.EncryptedKeyValue = Convert.FromBase64String(xml.GetAttribute("encryptedKeyValue")); } } CheckPassword(Encryption, KeyVerifier, KeyEncParams, KeyKey); DataKey.Key = KeyKey.Key; DataKey.Password = KeyKey.Password; DataKey.CalcDataIV(0); return(DecryptStream(DataStream, DataEncParams, DataKey)); }
private void ReadPropSectionHeader(TOle2File OleFile) { long PropStart = OleFile.Position; byte[] PropSectionHeader = new byte[8]; OleFile.Read(PropSectionHeader, PropSectionHeader.Length); int PropCount = (int)BitOps.GetWord(PropSectionHeader, 4); TPropIdOffset[] PropOffsets = new TPropIdOffset[PropCount]; for (int i = 0; i < PropOffsets.Length; i++) { OleFile.Read(PropSectionHeader, 8); //Reuse the array to avoid allocate more memory PropOffsets[i].Id = (UInt32)BitOps.GetInt32(PropSectionHeader, 0); PropOffsets[i].Offset = (UInt32)BitOps.GetInt32(PropSectionHeader, 4); } Array.Sort(PropOffsets); for (int i = 0; i < PropOffsets.Length; i++) { OleFile.SeekForward(PropOffsets[i].Offset + PropStart); ReadProperty(OleFile, PropOffsets[i].Id); } //Get the actual codepage and convert the strings int Cp = 1252; //windows western encoding. object Cpo; if (PropertyList.TryGetValue(1, out Cpo)) { Cp = Convert.ToInt32(Cpo); } Encoding CodePage = Encoding.GetEncoding(Cp); UInt32[] Keys = new UInt32[PropertyList.Count]; PropertyList.Keys.CopyTo(Keys, 0); foreach (UInt32 key in Keys) { PropertyList[key] = ConvertStrings(PropertyList[key], CodePage); } }
internal static bool IsValidFile(Stream aStream) { using (TOle2File DataStream = new TOle2File(aStream, true)) { if (DataStream.NotXls97) { return(false); } if (!DataStream.SelectStream(XlsxConsts.EncryptionInfoString, true)) { return(false); } if (!DataStream.SelectStream(XlsxConsts.ContentString, true)) { return(false); } } return(true); }
private void ReadProperty(TOle2File Ole2File, uint Id) { if (Id == 0) //This is the name list. { PropertyList.Add(Id, GetNameDictionary(Ole2File)); return; } byte[] PropTypeArray = new byte[4]; Ole2File.Read(PropTypeArray, PropTypeArray.Length); Int32 PropType = BitOps.GetInt32(PropTypeArray, 0); if (Id == 1 && PropType == (int)TPropertyTypes.VT_I2) //H a c k to get the correct codepage. It should not be negative. { PropType = (int)TPropertyTypes.VT_UI2; } object Value = GetOneProperty(Ole2File, PropType); PropertyList.Add(Id, Value); }
private static Stream ReadStandardEncryptionInfo(TOle2File DataStream, TEncryptionData Encryption) { byte[] RecordHeaderLen = new byte[4]; DataStream.Read(RecordHeaderLen, RecordHeaderLen.Length); long EncryptionHeaderSize = BitOps.GetCardinal(RecordHeaderLen, 0); byte[] EncryptionHeader = new byte[EncryptionHeaderSize]; DataStream.Read(EncryptionHeader, EncryptionHeader.Length); long AlgId = BitOps.GetCardinal(EncryptionHeader, 8); long KeyBits = BitOps.GetCardinal(EncryptionHeader, 16); TEncryptionParameters EncParams = TEncryptionParameters.CreateStandard(GetStandardEncAlg(AlgId)); byte[] VerifierBytes = new byte[DataStream.Length - DataStream.Position]; DataStream.Read(VerifierBytes, VerifierBytes.Length); TStandardEncryptionVerifier Verifier = ReadStandardVerifier(VerifierBytes); TEncryptionKey Key = new TStandardEncryptionKey(ReadStandardSalt(VerifierBytes), (int)KeyBits / 8); CheckPassword(Encryption, Verifier, EncParams, Key); return(DecryptStream(DataStream, EncParams, Key)); }
internal void Write(TOle2File OleFile) { WriteHeader(OleFile); }
private object GetOneProperty(TOle2File Ole2File, int PropType) { if ((PropType & (int)TPropertyTypes.VT_VECTOR) != 0) { byte[] i4 = new byte[4]; Ole2File.Read(i4, i4.Length); object[] Vector = new object[BitOps.GetInt32(i4, 0)]; for (int i = 0; i < Vector.Length; i++) { Vector[i] = GetOneProperty(Ole2File, PropType & ~(int)TPropertyTypes.VT_VECTOR); } return(Vector); } switch ((TPropertyTypes)(PropType & 0xFF)) { case TPropertyTypes.VT_EMPTY: return(null); case TPropertyTypes.VT_I2: byte[] i2 = new byte[2]; Ole2File.Read(i2, i2.Length); return(BitConverter.ToInt16(i2, 0)); case TPropertyTypes.VT_UI2: //This is not really suported, but we need to convert the CodePage to a Signed int. byte[] ui2 = new byte[2]; Ole2File.Read(ui2, ui2.Length); return((Int32)BitConverter.ToUInt16(ui2, 0)); case TPropertyTypes.VT_I4: byte[] i4 = new byte[4]; Ole2File.Read(i4, i4.Length); return(BitOps.GetInt32(i4, 0)); case TPropertyTypes.VT_R4: byte[] d4 = new byte[4]; Ole2File.Read(d4, d4.Length); return(BitConverter.ToSingle(d4, 0)); case TPropertyTypes.VT_R8: byte[] d8 = new byte[8]; Ole2File.Read(d8, d8.Length); return(BitConverter.ToDouble(d8, 0)); case TPropertyTypes.VT_CY: byte[] cy = new byte[8]; Ole2File.Read(cy, cy.Length); return(TCompactFramework.DecimalFromOACurrency(BitConverter.ToInt64(cy, 0))); case TPropertyTypes.VT_DATE: byte[] dd = new byte[8]; Ole2File.Read(dd, dd.Length); DateTime Dt; if (!FlxDateTime.TryFromOADate(BitConverter.ToDouble(dd, 0), false, out Dt)) { return(DateTime.MinValue); } return(Dt.Date); case TPropertyTypes.VT_BSTR: byte[] sl = new byte[4]; Ole2File.Read(sl, sl.Length); UInt32 StrLen = BitConverter.ToUInt32(sl, 0); if (StrLen <= 1) { return(String.Empty); //StrLen includes the trailing #0 } byte[] Str = new byte[StrLen - 1]; Ole2File.Read(Str, Str.Length); Ole2File.SeekForward(Ole2File.Position + 1); //go over the 0 byte. This is needed for vectors/arrays. return(new TUnconvertedString(Str, false)); case TPropertyTypes.VT_BOOL: byte[] bl = new byte[2]; Ole2File.Read(bl, bl.Length); return(BitConverter.ToInt16(bl, 0) == 0? false: true); case TPropertyTypes.VT_VARIANT: byte[] VariantTypeArray = new byte[4]; Ole2File.Read(VariantTypeArray, VariantTypeArray.Length); Int32 VariantType = BitOps.GetInt32(VariantTypeArray, 0); return(GetOneProperty(Ole2File, VariantType)); case TPropertyTypes.VT_I8: byte[] i8 = new byte[8]; Ole2File.Read(i8, i8.Length); return(BitConverter.ToInt64(i8, 0)); case TPropertyTypes.VT_LPSTR: byte[] sl2 = new byte[4]; Ole2File.Read(sl2, sl2.Length); UInt32 StrLen2 = BitConverter.ToUInt32(sl2, 0); if (StrLen2 <= 1) { return(String.Empty); //StrLen includes the trailing #0 } byte[] Str2 = new byte[StrLen2 - 1]; Ole2File.Read(Str2, Str2.Length); Ole2File.SeekForward(Ole2File.Position + 1); //go over the 0 byte. This is needed for vectors/arrays. return(new TUnconvertedString(Str2, false)); case TPropertyTypes.VT_LPWSTR: byte[] sl3 = new byte[4]; Ole2File.Read(sl3, sl3.Length); UInt32 StrLen3 = BitConverter.ToUInt32(sl3, 0); if (StrLen3 <= 1) { return(String.Empty); //StrLen includes the trailing #0 } byte[] Str3 = new byte[(StrLen3 - 1) * 2]; Ole2File.SeekForward(Ole2File.Position + 2); //go over the 0 byte. This is needed for vectors/arrays. Ole2File.Read(Str3, Str3.Length); return(new TUnconvertedString(Str3, true)); case TPropertyTypes.VT_FILETIME: byte[] ft = new byte[8]; Ole2File.Read(ft, ft.Length); return(DateTime.FromFileTime(BitConverter.ToInt64(ft, 0))); case TPropertyTypes.VT_BLOB: byte[] blb = new byte[4]; Ole2File.Read(blb, blb.Length); UInt32 BlobLen = BitConverter.ToUInt32(blb, 0); if (BlobLen <= 0) { return(new byte[0]); //BlobLen does not includes trailing #0 } byte[] Blob = new byte[BlobLen]; Ole2File.Read(Blob, Blob.Length); return(Blob); } return(null); //Not a supported type. }