.NET MAUI Android发布版中Renci.SshNet无法创建SHA512哈希算法的问题
问题描述
基于.NET MAUI开发的SFTP文件下载应用,调试阶段连接服务器完全正常,但发布Android版本(目标API 13,最低API 9)后,调用SFTP连接逻辑时抛出以下错误:
Could not create HashAlgorithm from
SHA512. Arg_ParamName_Name, hashAlgorithmName
at Renci.SshNet.Security.Cryptography.RsaDigitalSignature..ctor(RsaKey rsaKey, HashAlgorithmName hashAlgorithmName)
at Renci.SshNet.PrivateKeyFile.Open(Stream privateKey, String passPhrase)
at Renci.SshNet.PrivateKeyFile..ctor(Stream privateKey, String passPhrase)
连接核心代码如下:
public void Connect() { MemoryStream keyStream = new(Encoding.ASCII.GetBytes(privateKey)); keyFile = new PrivateKeyFile(keyStream, privateKeyPassword); PrivateKeyConnectionInfo keyConnectionInfo = new(host, port, username, keyFile); client = new SftpClient(keyConnectionInfo); client.Connect(); }
解决方案
1. 避免AOT编译裁剪哈希算法
.NET MAUI Android发布版默认启用AOT编译和链接优化,会自动裁剪未被直接引用的程序集成员,SHA512算法实现可能被误删。可通过以下两种方式配置:
- 修改项目csproj文件:在Release配置中添加链接跳过规则
<PropertyGroup Condition="'$(Configuration)' == 'Release'"> <AndroidLinkMode>Full</AndroidLinkMode> <AndroidLinkSkip>System.Security.Cryptography</AndroidLinkSkip> </PropertyGroup> - 添加AndroidManifest元数据:在
Platforms/Android/AndroidManifest.xml的<application>标签内添加<meta-data android:name="com.microsoft.dotnet.maui.enable-crypto-provider" android:value="true" />
2. 显式引用SHA512算法
在连接代码中显式创建SHA512实例,强制编译器保留该算法的实现代码,避免被AOT裁剪:
public void Connect() { // 显式引用,防止AOT编译时裁剪SHA512实现 _ = SHA512.Create(); MemoryStream keyStream = new(Encoding.UTF8.GetBytes(privateKey)); keyFile = new PrivateKeyFile(keyStream, privateKeyPassword); PrivateKeyConnectionInfo keyConnectionInfo = new(host, port, username, keyFile); client = new SftpClient(keyConnectionInfo); client.Connect(); }
3. 修正密钥编码方式
原代码使用Encoding.ASCII读取私钥,若密钥包含非ASCII字符会导致内容损坏,改为Encoding.UTF8确保密钥流完整:
MemoryStream keyStream = new(Encoding.UTF8.GetBytes(privateKey));
4. 升级Renci.SshNet版本
旧版本的Renci.SshNet可能存在.NET MAUI Android环境下的兼容性问题,升级到最新稳定版可解决部分AOT编译相关的哈希算法适配问题。
原因说明
调试模式下,.NET MAUI未启用AOT和链接优化,所有程序集成员都会被加载,SHA512算法可正常创建;发布版启用优化后,未被代码直接引用的算法实现会被裁剪,导致运行时无法找到SHA512的创建入口,从而抛出错误。
内容的提问来源于stack exchange,提问作者fikewek832

