private Stream CreateXTSStream(File file, long?start = null, long?end = null) { var pub = CryptoUtil.GetCryptoPublicInfo(_cloud, file); var key = CryptoUtil.GetCryptoKey(_cloud.Account.Credentials.PasswordCrypt, pub.Salt); var xts = XtsAes256.Create(key, pub.IV); long fileLength = file.OriginalSize; long requestedOffset = start ?? 0; long requestedEnd = end ?? fileLength; long alignedOffset = requestedOffset / XTSSectorSize * XTSSectorSize; long alignedEnd = requestedEnd % XTSBlockSize == 0 ? requestedEnd : (requestedEnd / XTSBlockSize + 1) * XTSBlockSize; if (alignedEnd == 0) { alignedEnd = 16; } var downStream = _cloud.Account.RequestRepo.GetDownloadStream(file, alignedOffset, alignedEnd); ulong startSector = (ulong)alignedOffset / XTSSectorSize; int trimStart = (int)(requestedOffset - alignedOffset); uint trimEnd = alignedEnd == fileLength ? file.ServiceInfo.CryptInfo.AlignBytes : (uint)(alignedEnd - requestedEnd); var xtsStream = new XTSReadOnlyStream(downStream, xts, XTSSectorSize, startSector, trimStart, trimEnd); return(xtsStream); }
private Stream GetCryptoStream(File file, FileUploadedDelegate onUploaded) { var info = CryptoUtil.GetCryptoKeyAndSalt(_cloud.Account.Credentials.PasswordCrypt); var xts = XtsAes256.Create(info.Key, info.IV); file.ServiceInfo.CryptInfo = new CryptInfo { PublicKey = new CryptoKeyInfo { Salt = info.Salt, IV = info.IV }, AlignBytes = (uint)(file.Size % XTSWriteOnlyStream.BlockSize != 0 ? XTSWriteOnlyStream.BlockSize - file.Size % XTSWriteOnlyStream.BlockSize : 0) }; var size = file.OriginalSize % XTSWriteOnlyStream.BlockSize == 0 ? file.OriginalSize.DefaultValue : (file.OriginalSize / XTSWriteOnlyStream.BlockSize + 1) * XTSWriteOnlyStream.BlockSize; var ustream = new SplittedUploadStream(file.FullPath, _cloud, size, false, file.ServiceInfo.CryptInfo); if (onUploaded != null) { ustream.FileUploaded += onUploaded; } // ReSharper disable once RedundantArgumentDefaultValue var encustream = new XTSWriteOnlyStream(ustream, xts, XTSWriteOnlyStream.DefaultSectorSize); return(encustream); }
protected override async Task InitMetadataImplAsync(CancellationToken cancel = default) { Memory <byte> firstSectorData = new byte[XtsAesMetaDataSize]; // ヘッダの読み込みを試行する int readSize = await this.PhysicalReadAsync(0, firstSectorData, cancel); if (readSize == XtsAesMetaDataSize) { var metaDataParseResult = TryParseMetaData(firstSectorData); metaDataParseResult.ThrowIfException(); var metaData = metaDataParseResult.Value !; // パスワード検査 if (Secure.VeritySaltedPassword(metaData.SaltedPassword, this.CurrentPassword) == false) { throw new CoresException("XtsAesRandomAccess: Incorrect password."); } // 秘密鍵解読 var decrypted = ChaChaPoly.EasyDecryptWithPassword(metaData.MasterKeyEncryptedByPassword._GetHexBytes(), this.CurrentPassword); decrypted.ThrowIfException(); // 秘密鍵サイズ検査 if (decrypted.Value.Length != XtsAesKeySize) { throw new CoresException("XtsAesRandomAccess: decrypted.Value.Length != XtsAesKeySize"); } this.CurrentMasterKey = decrypted.Value; this.CurrentMetaData = metaData; } else if (readSize == 0) { // ファイルの内容が存在しない // マスターキーを新規作成する this.CurrentMasterKey = Secure.Rand(XtsAesKeySize); // メタデータを新規作成する var metaData = new XtsAesRandomAccessMetaData { Version = 1, VirtualSize = 0, SaltedPassword = Secure.SaltPassword(this.CurrentPassword), MasterKeyEncryptedByPassword = ChaChaPoly.EasyEncryptWithPassword(this.CurrentMasterKey, this.CurrentPassword)._GetHexString(), }; this.CurrentMetaData = metaData; // メタデータを書き込みする await WriteMetaDataAsync(cancel); } else { // 不正 ここには来ないはず throw new CoresException($"XtsAesRandomAccess: Invalid readSize: {readSize}"); } // XTS を作成 this.CurrentXts = XtsAes256.Create(this.CurrentMasterKey.ToArray()); this.CurrentEncrypter = this.CurrentXts.CreateEncryptor(); this.CurrentDescrypter = this.CurrentXts.CreateDecryptor(); }