我正在开发一个 Flutter 应用程序,其中涉及从互联网获取 pdf 文件,加密并将其存储在应用程序文件目录中,然后检索、解密它以在应用程序中显示。 为此,我使用 https://pub.dev/packages/encrypt 和 Syncfusion pdf 查看器。 但是在解密和显示文件时我得到了
ArgumentError{Invalid argument (position): Invalid Position:-1}
在调试模式下运行时在 SfPdfViewer 上。 代码是:
`SfPdfViewer.network(
widget.file!.link!,
key: _pdfViewerKey,
onDocumentLoaded: (PdfDocumentLoadedDetails details) async {
// final Directory tempPath = await getApplicationDocumentsDirectory();
// _tempFile = await File('${tempPath.path}/${widget.file!.title}.pdf')
// .writeAsBytes( await details.document.save());
}):FutureBuilder<Uint8List>(
future: getFileBytes(),
builder:(context,snapshot){
if(snapshot.hasData)
{
logger.i("Snapshot Data is ${snapshot.data}");
return SfPdfViewer.memory(snapshot.data!,key: _pdfViewerKey, );
}
else if(snapshot.hasData)
{
snapshot.printError();
return Text('Error');
}
else
{
return const Center(child: CircularProgressIndicator());
}
}
)
);
}
Future<Uint8List> getFileBytes() async
{
return await fileController.getDecryptedFile(name: widget.file!.title!);
}`
下载、加密、解密方法有:
Future<void> downloadFile({required Files file})async
{
logger.e("Link of file to be downloaded is ${file.link}");
Response response=await download(url: file.link!);
final directory = await getApplicationDocumentsDirectory();
final filesDirectory = await Directory('${directory.path}/files').create(recursive: true);
String filePath='${filesDirectory.path}/${file.title!}.aes';
logger.i("Length of key is ${key.length}");
final encryptor=Encrypter(AES(key,padding: null));
logger.i("Unencrypted bytes: ${response.data}");
final encryptedBytes = encryptor.encryptBytes(response.data,iv: iv,);
final decryptedBytes = encryptor.decryptBytes(encryptedBytes,iv: iv,associatedData: encryptedBytes.bytes);
logger.i("encrypted bytes: ${encryptedBytes}");
final encryptedFile=File(filePath);
encryptedFile.writeAsBytesSync(encryptedBytes.bytes);
changeDownloadStatus(true);
}
Future<dynamic> download({required String url}) async
{
try{
String token=url.substring(url.indexOf("token")+7,url.indexOf("_gl"));
String alt=url.substring( url.indexOf("alt=")+5,url.indexOf("token="));
String gl=url.substring(url.indexOf("_gl=")+5);
Map<String,String> query={
"token":token,
"alt":alt,
"_gl":gl
};
Response response =await Dio().get(url.substring(0,url.indexOf("?")),options: Options(responseType: ResponseType.bytes,
followRedirects: false,contentType: "application/pdf"),queryParameters: query);
logger.i(response.data);
changeDownloadStatus(true);
return response;
}
on Exception catch(e)
{
logger.e(e.toString());
}
}
Future<Uint8List> getDecryptedFile({required String name}) async
{
final directory = await getApplicationDocumentsDirectory();
final filesDirectory = Directory('${directory.path}/files');
String filePath='${filesDirectory.path}/$name.aes';
File encryptedfile=File(filePath);
bool isPresent=await encryptedfile.exists();
logger.i("File at path $filePath is present $isPresent");
Uint8List encryptedBytes=encryptedfile.readAsBytesSync();
logger.i("encrypted bytes: ${encryptedBytes}");
// Decrypt the file
final encryptor=Encrypter(AES(key,padding: null));
final decryptedBytes=encryptor.decryptBytes(Encrypted(encryptedBytes),iv: iv,associatedData: encryptedBytes);
return Uint8List.fromList(decryptedBytes);
}
Key 和 Iv 的获取方式为:
final iv=IV.fromLength(16);
final key=Key.fromSecureRandom(32);
我在日志中得到一个列表,其中包含未加密字节和解密字节的相同数据。 此外,当在加密器对象中使用默认填充时,我在解密字节方法中得到无效或损坏的填充。 问题出在哪里?
我们审查了提供的示例,并创建了一个类似的应用程序,该应用程序使用您通过 https://pub.dev/packages/encrypt 共享的包来加密和解密文件。我们已成功在 SfPdfViewer 中加载解密的字节,并且它在我们这边正确显示了 PDF 文档。我附上了示例的代码片段供您参考。请尝试此操作,如果您仍然遇到任何问题,请告诉我们。如果是,请分享重现该问题的修改后的代码示例。这将有助于我们尽快提供及时的解决方案。
代码片段:
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_pdfviewer/pdfviewer.dart';
import 'package:encrypt/encrypt.dart' as encrypt;
import 'package:http/http.dart' as http;
void main() {
runApp(MaterialApp(
title: 'Syncfusion PDF Viewer Demo',
home: HomePage(),
));
}
/// Represents Homepage for Navigation
class HomePage extends StatefulWidget {
@override
_HomePage createState() => _HomePage();
}
class _HomePage extends State<HomePage> {
final GlobalKey<SfPdfViewerState> _pdfViewerKey = GlobalKey();
Uint8List? _documentBytes;
@override
void initState() {
super.initState();
loadPdfDocument();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Syncfusion Flutter PDF Viewer'),
),
body: _documentBytes != null
? SfPdfViewer.memory(_documentBytes!)
: Container());
}
/// Handling the encryption, decryption and load the document in SfPDfViewer.
Future<void> loadPdfDocument() async {
const url =
'https://cdn.syncfusion.com/content/PDFViewer/flutter-succinctly.pdf';
final response = await http.get(Uri.parse(url));
if (response.statusCode == 200) {
final fileBytes = response.bodyBytes;
final key = encrypt.Key.fromSecureRandom(32);
final iv = encrypt.IV.fromSecureRandom(16);
final encrypter =
encrypt.Encrypter(encrypt.AES(key, mode: encrypt.AESMode.ctr));
// Encrypt the file
final encryptedBytes = encrypter.encryptBytes(
fileBytes,
iv: iv,
);
// Decrypt the file
final decryptedBytes = encrypter.decryptBytes(encryptedBytes, iv: iv);
// For loading the decrypted bytes in SfPdfViewer.
_documentBytes = Uint8List.fromList(decryptedBytes);
setState(() {});
}
}
}