Exemple #1
0
        public AesXtsFile(OpenMode mode, IFile baseFile, U8String path, ReadOnlySpan <byte> kekSeed, ReadOnlySpan <byte> verificationKey, int blockSize)
        {
            Mode            = mode;
            BaseFile        = baseFile;
            Path            = path;
            KekSeed         = kekSeed.ToArray();
            VerificationKey = verificationKey.ToArray();
            BlockSize       = blockSize;

            Header = new AesXtsFileHeader(BaseFile);

            baseFile.GetSize(out long fileSize).ThrowIfFailure();

            if (!Header.TryDecryptHeader(Path.ToString(), KekSeed, VerificationKey))
            {
                ThrowHelper.ThrowResult(ResultFs.AesXtsFileHeaderInvalidKeys.Value, "NAX0 key derivation failed.");
            }

            if (HeaderLength + Utilities.AlignUp(Header.Size, 0x10) > fileSize)
            {
                ThrowHelper.ThrowResult(ResultFs.AesXtsFileTooShort.Value, "NAX0 key derivation failed.");
            }

            var fileStorage = new FileStorage2(baseFile);
            var encStorage  = new SubStorage(fileStorage, HeaderLength, fileSize - HeaderLength);

            encStorage.SetResizable(true);

            BaseStorage = new CachedStorage(new Aes128XtsStorage(encStorage, Header.DecryptedKey1, Header.DecryptedKey2, BlockSize, true), 4, true);
        }
Exemple #2
0
        protected override Result DoRenameFile(U8Span oldPath, U8Span newPath)
        {
            // todo: Return proper result codes

            AesXtsFileHeader header = ReadXtsHeader(oldPath.ToString(), oldPath.ToString());

            Result rc = BaseFileSystem.RenameFile(oldPath, newPath);

            if (rc.IsFailure())
            {
                return(rc);
            }

            try
            {
                WriteXtsHeader(header, newPath.ToString(), newPath.ToString());
            }
            catch (Exception)
            {
                BaseFileSystem.RenameFile(newPath, oldPath);
                WriteXtsHeader(header, oldPath.ToString(), oldPath.ToString());

                throw;
            }

            return(Result.Success);
        }
Exemple #3
0
        /// <summary>
        /// Creates a new <see cref="AesXtsFile"/> using the provided key.
        /// </summary>
        /// <param name="path">The full path of the file to create.</param>
        /// <param name="size">The initial size of the created file.</param>
        /// <param name="options">Flags to control how the file is created.
        /// Should usually be <see cref="CreateFileOptions.None"/></param>
        /// <param name="key">The 256-bit key containing a 128-bit data key followed by a 128-bit tweak key.</param>
        public Result CreateFile(U8Span path, long size, CreateFileOptions options, byte[] key)
        {
            long containerSize = AesXtsFile.HeaderLength + Utilities.AlignUp(size, 0x10);

            Result rc = BaseFileSystem.CreateFile(path, containerSize, options);

            if (rc.IsFailure())
            {
                return(rc);
            }

            var header = new AesXtsFileHeader(key, size, path.ToString(), KekSource, ValidationKey);

            rc = BaseFileSystem.OpenFile(out IFile baseFile, path, OpenMode.Write);
            if (rc.IsFailure())
            {
                return(rc);
            }

            using (baseFile)
            {
                rc = baseFile.Write(0, header.ToBytes(false));
                if (rc.IsFailure())
                {
                    return(rc);
                }
            }

            return(Result.Success);
        }
Exemple #4
0
        private void RenameDirectoryImpl(string srcDir, string dstDir, bool doRollback)
        {
            foreach (DirectoryEntryEx entry in this.EnumerateEntries(dstDir, "*"))
            {
                string subSrcPath = $"{srcDir}/{entry.Name}";
                string subDstPath = $"{dstDir}/{entry.Name}";

                if (entry.Type == DirectoryEntryType.Directory)
                {
                    RenameDirectoryImpl(subSrcPath, subDstPath, doRollback);
                }

                if (entry.Type == DirectoryEntryType.File)
                {
                    if (doRollback)
                    {
                        if (TryReadXtsHeader(subDstPath, subDstPath, out AesXtsFileHeader header))
                        {
                            WriteXtsHeader(header, subDstPath, subSrcPath);
                        }
                    }
                    else
                    {
                        AesXtsFileHeader header = ReadXtsHeader(subDstPath, subSrcPath);
                        WriteXtsHeader(header, subDstPath, subDstPath);
                    }
                }
            }
        }
Exemple #5
0
        protected override Result RenameFileImpl(string oldPath, string newPath)
        {
            oldPath = PathTools.Normalize(oldPath);
            newPath = PathTools.Normalize(newPath);

            // todo: Return proper result codes

            AesXtsFileHeader header = ReadXtsHeader(oldPath, oldPath);

            BaseFileSystem.RenameFile(oldPath, newPath);

            try
            {
                WriteXtsHeader(header, newPath, newPath);
            }
            catch (Exception)
            {
                BaseFileSystem.RenameFile(newPath, oldPath);
                WriteXtsHeader(header, oldPath, oldPath);

                throw;
            }

            return(Result.Success);
        }
Exemple #6
0
        public AesXtsFile(OpenMode mode, IFile baseFile, string path, ReadOnlySpan <byte> kekSeed, ReadOnlySpan <byte> verificationKey, int blockSize)
        {
            Mode            = mode;
            BaseFile        = baseFile;
            Path            = path;
            KekSeed         = kekSeed.ToArray();
            VerificationKey = verificationKey.ToArray();
            BlockSize       = blockSize;

            Header = new AesXtsFileHeader(BaseFile);

            baseFile.GetSize(out long fileSize).ThrowIfFailure();

            if (!Header.TryDecryptHeader(Path, KekSeed, VerificationKey))
            {
                ThrowHelper.ThrowResult(ResultFs.AesXtsFileHeaderInvalidKeys, "NAX0 key derivation failed.");
            }

            if (HeaderLength + Util.AlignUp(Header.Size, 0x10) > fileSize)
            {
                ThrowHelper.ThrowResult(ResultFs.AesXtsFileTooShort, "NAX0 key derivation failed.");
            }

            IStorage encStorage = BaseFile.AsStorage().Slice(HeaderLength, Util.AlignUp(Header.Size, 0x10));

            BaseStorage = new CachedStorage(new Aes128XtsStorage(encStorage, Header.DecryptedKey1, Header.DecryptedKey2, BlockSize, true), 4, true);
        }
Exemple #7
0
        private void WriteXtsHeader(AesXtsFileHeader header, string filePath, string keyPath)
        {
            Debug.Assert(PathTools.IsNormalized(filePath.AsSpan()));
            Debug.Assert(PathTools.IsNormalized(keyPath.AsSpan()));

            header.EncryptHeader(keyPath, KekSource, ValidationKey);

            BaseFileSystem.OpenFile(out IFile file, filePath.ToU8Span(), OpenMode.ReadWrite);

            using (file)
            {
                file.Write(0, header.ToBytes(false), WriteOption.Flush).ThrowIfFailure();
            }
        }
Exemple #8
0
        private bool TryReadXtsHeader(string filePath, string keyPath, out AesXtsFileHeader header)
        {
            Debug.Assert(PathTools.IsNormalized(filePath.AsSpan()));
            Debug.Assert(PathTools.IsNormalized(keyPath.AsSpan()));

            header = null;

            Result rc = BaseFileSystem.OpenFile(out IFile file, filePath.ToU8Span(), OpenMode.Read);

            if (rc.IsFailure())
            {
                return(false);
            }

            using (file)
            {
                header = new AesXtsFileHeader(file);

                return(header.TryDecryptHeader(keyPath, KekSource, ValidationKey));
            }
        }