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); }
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); }
/// <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); }
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); } } } }
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); }
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); }
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(); } }
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)); } }