/// <summary> /// Loads a <see cref="AegisBondArchive"/> from disk. This operation does not unlock the archive. /// </summary> /// <param name="fileSettings">Settings for where the archive and related files are stored.</param> /// <returns>The loaded <see cref="AegisBondArchive"/>.</returns> public static AegisArchive Load(SecureArchiveFileSettings fileSettings) { ArgCheck.IsValid(fileSettings, nameof(fileSettings)); ZipArchive tempSecureArchive = null; AegisArchive archive = null; try { // Open the secure archive and read the metadata entry. tempSecureArchive = OpenSecureArchiveFile(fileSettings); var metadataEntry = tempSecureArchive.GetEntry(AegisConstants.SecureArchiveMetadataEntryName); if (metadataEntry is null) { throw new ArchiveCorruptedException("The secure archive does not contain any internal metadata!"); } using var metadataReader = new StreamReader(metadataEntry.Open()); var metadataJson = metadataReader.ReadToEnd(); var metadata = JsonSerializer.Deserialize <SecureArchiveMetadata>(metadataJson); if (metadata is null) { throw new ArchiveCorruptedException("Unable to parse the archive internal metadata!"); } archive = new AegisArchive { ArchiveMetadata = metadata, FileSettings = fileSettings, SecureArchive = tempSecureArchive, }; // We've transfered dispose ownership of tempSecureArchive to the archive. tempSecureArchive = null; } finally { tempSecureArchive?.Dispose(); } return(archive); }
/// <summary> /// Creates a new <see cref="AegisArchive"/> that contains no files. /// </summary> /// <param name="fileSettings">Settings for where the archive and related files are stored.</param> /// <param name="creationParameters">The <see cref="SecureArchiveCreationParameters"/> to use when creating the archive.</param> /// <returns>A new <see cref="AegisArchive"/> that is opened but not yet persisted to disk.</returns> public static AegisArchive CreateNew( SecureArchiveFileSettings fileSettings, SecureArchiveCreationParameters creationParameters) { ArgCheck.IsValid(fileSettings, nameof(fileSettings)); ArgCheck.IsValid(creationParameters, nameof(creationParameters)); var currentTime = DateTimeOffset.UtcNow; var archiveId = Guid.NewGuid(); ArchiveKey tempArchiveKey = null; AegisArchive tempArchive = null; AegisArchive archive = null; try { tempArchiveKey = ArchiveKey.CreateNew(creationParameters.SecuritySettings); // Derive and authorize the first user key. var keyDerivationSalt = CryptoHelpers.GetRandomBytes(creationParameters.KeyDerivationSaltSizeInBytes); var firstUserKeyAuthorization = UserKeyAuthorizationExtensions.CreateNewAuthorization( creationParameters.FirstKeyAuthorizationParams, keyDerivationSalt, tempArchiveKey, creationParameters.SecuritySettings); var authCanary = tempArchiveKey.Encrypt( CryptoHelpers.GetCryptoStrategy(creationParameters.SecuritySettings.EncryptionAlgo), archiveId.ToByteArray()); var archiveMetadata = new SecureArchiveMetadata { Id = archiveId, SecuritySettings = creationParameters.SecuritySettings, CreateTime = currentTime, LastModifiedTime = currentTime, KeyDerivationSalt = new List <byte>(keyDerivationSalt), AuthCanary = authCanary, UserKeyAuthorizations = new List <UserKeyAuthorization> { firstUserKeyAuthorization }, }; tempArchive = new AegisArchive { ArchiveMetadata = archiveMetadata, ArchiveKey = tempArchiveKey, FileSettings = fileSettings, FileIndex = new FileIndex(), SecureArchive = OpenSecureArchiveFile(fileSettings, createNewArchive: true), }; tempArchive.PersistMetadata(); // Transfer the archive reference to the return variable. archive = tempArchive; tempArchive = null; // Dispose ownership of the archive key now belongs to the archive. tempArchiveKey = null; } finally { tempArchive?.Dispose(); tempArchiveKey?.Dispose(); } return(archive); }