-
Notifications
You must be signed in to change notification settings - Fork 7
Description
Сейчас для совместимости с некоторыми сторонними реализациями (ФСС) необходимо осуществлять импорт ключа 12 госта с использование старого CryptoProKeyWrap. Так как определить тип KeyWrap по ключу внутри Xml невозможно, то делаем так
private SymmetricAlgorithm CryptoProUnwrap(byte[] wrapped)
{
try
{
return this.CryptoProUnwrap(wrapped, GostConstants.CALG_PRO12_EXPORT);
}
catch (CryptographicException ex)
{
if (Marshal.GetHRForException(ex) == -2146893819)
{
// bad data - пробуем импорт на старом алгоритме
return this.CryptoProUnwrap(wrapped, GostConstants.CALG_PRO_EXPORT);
}
else
{
throw;
}
}
}Проблема возникает при использовании метода ImportKeyBlob
internal static int ImportKeyBlob(byte[] keyBlob,
SafeProvHandle hProv, CspProviderFlags flags,
SafeKeyHandle hImportKey, out SafeKeyHandle hKey)
{
int keyFlags = MapCspKeyFlags((int)flags);
bool ret = CapiHelper.CryptImportKey(hProv, keyBlob,
keyBlob.Length, hImportKey, keyFlags, out hKey);
if (!ret)
throw new CryptographicException(Marshal.GetLastWin32Error());
int algid_class = BitConverter.ToInt32(keyBlob, 4) & (7 << 13);
if (algid_class == (5 << 13))
return (int)KeyNumber.Exchange;
return (int)KeyNumber.Signature;
}Так как для Unix Marshal.GetLastWin32Error() вернёт некорректный код ошибки. При исправлении на
internal static int ImportKeyBlob(byte[] keyBlob,
SafeProvHandle hProv, CspProviderFlags flags,
SafeKeyHandle hImportKey, out SafeKeyHandle hKey)
{
int keyFlags = MapCspKeyFlags((int)flags);
bool ret = CapiHelper.CryptImportKey(hProv, keyBlob,
keyBlob.Length, hImportKey, keyFlags, out hKey);
if (!ret)
{
var hr = Interop.CPError.GetHRForLastWin32Error();
throw hr.ToCryptographicException();
}
int algid_class = BitConverter.ToInt32(keyBlob, 4) & (7 << 13);
if (algid_class == (5 << 13))
return (int)KeyNumber.Exchange;
return (int)KeyNumber.Signature;
}работает корректно.
Проблема технически может возникать и в других сценариях, ибо код CapiHelper полностью перенесён из Шарпея, и обработка ошибок полностью виндовая, на unix возможны и другие некорректные коды. С виду мы больше нигде по ним не ветвимся, поэтому править массово пока не будем (из за опасений, что получение кода ошибки в других методах теоретически может приходить к перетиранию кода, и тогда будем получать ошибку и на windows).
Хорошо добывать бы тест на это (возможно в рамках LibCore с переносом сюда).