diff --git a/src/KeyKeeper/PasswordStore/FileFormatUtil.cs b/src/KeyKeeper/PasswordStore/FileFormatUtil.cs new file mode 100644 index 0000000..c98ccaf --- /dev/null +++ b/src/KeyKeeper/PasswordStore/FileFormatUtil.cs @@ -0,0 +1,45 @@ +using System; +using System.IO; +using System.Text; + +namespace KeyKeeper.PasswordStore; + +static class FileFormatUtil +{ + public static int WriteVarUint16(Stream str, ulong number) + { + int size = 0; + do { + ushort portion = (ushort)(number & 0x7fff); + number >>= 15; + if (number != 0) + portion |= 1 << 15; + size += 2; + str.WriteByte((byte)(portion & 0xff)); + str.WriteByte((byte)(portion >> 8)); + } + while (number != 0); + return size; + } + + public static int WriteU8TaggedString(Stream str, string s) + { + byte[] b = Encoding.UTF8.GetBytes(s); + if (b.Length > 255) + throw new ArgumentException("string too long"); + str.WriteByte((byte)b.Length); + str.Write(b); + return b.Length + 1; + } + + public static int WriteU16TaggedString(Stream str, string s) + { + byte[] b = Encoding.UTF8.GetBytes(s); + if (b.Length > 65535) + throw new ArgumentException("string too long"); + str.WriteByte((byte)(b.Length & 0xff)); + str.WriteByte((byte)(b.Length >> 8)); + str.Write(b); + return b.Length + 2; + } +} \ No newline at end of file diff --git a/src/KeyKeeper/PasswordStore/IPassStoreEntry.cs b/src/KeyKeeper/PasswordStore/IPassStoreEntry.cs deleted file mode 100644 index dbeea0c..0000000 --- a/src/KeyKeeper/PasswordStore/IPassStoreEntry.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; - -namespace KeyKeeper.PasswordStore; - -public interface IPassStoreEntry -{ - string Name { get; set; } - PassStoreEntryType Type { get; set; } - DateTime CreationDate { get; } -} diff --git a/src/KeyKeeper/PasswordStore/PassStoreEntry.cs b/src/KeyKeeper/PasswordStore/PassStoreEntry.cs new file mode 100644 index 0000000..ed4513e --- /dev/null +++ b/src/KeyKeeper/PasswordStore/PassStoreEntry.cs @@ -0,0 +1,37 @@ +using System; +using System.IO; +using KeyKeeper.PasswordStore.Crypto; + +namespace KeyKeeper.PasswordStore; + +public abstract class PassStoreEntry +{ + public Guid Id { get; set; } + public DateTime CreationDate { get; protected set; } + public DateTime ModificationDate { get; set; } + public Guid IconType { get; set; } + public string Name { get; set; } + public PassStoreEntryType Type { get; set; } + + public void WriteToStream(Stream str) + { + MemoryStream tmp = new(); + BinaryWriter wr = new(tmp); + wr.Write(Id.ToByteArray()); + ulong timestamp = (ulong) new DateTimeOffset(CreationDate.ToUniversalTime()).ToUnixTimeSeconds(); + FileFormatUtil.WriteVarUint16(tmp, timestamp); + timestamp = (ulong) new DateTimeOffset(ModificationDate.ToUniversalTime()).ToUnixTimeSeconds(); + FileFormatUtil.WriteVarUint16(tmp, timestamp); + wr.Write(IconType.ToByteArray()); + FileFormatUtil.WriteU8TaggedString(tmp, Name); + wr.Write(InnerSerialize()); + byte[] serializedEntry = tmp.ToArray(); + tmp.Dispose(); + + wr = new(str); + wr.Write7BitEncodedInt(serializedEntry.Length); + wr.Write(serializedEntry); + } + + protected abstract byte[] InnerSerialize(); +}