Ejemplo n.º 1
0
        /// <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);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Opens a secure archive (zip) file on disk.
        /// </summary>
        /// <param name="fileSettings">The <see cref="SecureArchiveFileSettings"/> for the archive to open.</param>
        /// <param name="createNewArchive">Indicates whether we expect to be creating a new secure archive.</param>
        private static ZipArchive OpenSecureArchiveFile(SecureArchiveFileSettings fileSettings, bool createNewArchive = false)
        {
            if (createNewArchive)
            {
                // Create the output directory if it doesn't already exist.
                var directoryPath = Path.GetDirectoryName(fileSettings.Path);
                if (!string.IsNullOrWhiteSpace(directoryPath) && !Directory.Exists(directoryPath))
                {
                    Directory.CreateDirectory(directoryPath);
                }
            }
            else if (!File.Exists(fileSettings.Path))
            {
                throw new FileNotFoundException($"No archive file was found at {fileSettings.Path}", fileSettings.Path);
            }

            return(ZipFile.Open(fileSettings.Path, ZipArchiveMode.Update));
        }
Ejemplo n.º 3
0
        /// <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);
        }