aspnetcore/src/Microsoft.AspNetCore.Mvc.Ra.../Internal/SnkUtils.cs

88 lines
3.3 KiB
C#

// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Immutable;
using System.IO;
namespace Microsoft.AspNetCore.Mvc.Razor.ViewCompilation.Design.Internal
{
// Copied from https://github.com/dotnet/cli/blob/rel/1.0.0/src/Microsoft.DotNet.ProjectModel.Workspaces/SnkUtils.cs
public static class SnkUtils
{
const byte PUBLICKEYBLOB = 0x06;
const byte PRIVATEKEYBLOB = 0x07;
private const uint CALG_RSA_SIGN = 0x00002400;
private const uint CALG_SHA = 0x00008004;
private const uint RSA1 = 0x31415352; //"RSA1" publickeyblob
private const uint RSA2 = 0x32415352; //"RSA2" privatekeyblob
private const int VersionOffset = 1;
private const int ModulusLengthOffset = 12;
private const int ExponentOffset = 16;
private const int MagicPrivateKeyOffset = 8;
private const int MagicPublicKeyOffset = 20;
public static ImmutableArray<byte> ExtractPublicKey(byte[] snk)
{
ValidateBlob(snk);
if (snk[0] != PRIVATEKEYBLOB)
{
return ImmutableArray.Create(snk);
}
var version = snk[VersionOffset];
int modulusBitLength = ReadInt32(snk, ModulusLengthOffset);
uint exponent = (uint)ReadInt32(snk, ExponentOffset);
var modulus = new byte[modulusBitLength >> 3];
Array.Copy(snk, 20, modulus, 0, modulus.Length);
return CreatePublicKey(version, exponent, modulus);
}
private static void ValidateBlob(byte[] snk)
{
// 160 - the size of public key
if (snk.Length >= 160)
{
if (snk[0] == PRIVATEKEYBLOB && ReadInt32(snk, MagicPrivateKeyOffset) == RSA2 || // valid private key
snk[12] == PUBLICKEYBLOB && ReadInt32(snk, MagicPublicKeyOffset) == RSA1) // valid public key
{
return;
}
}
throw new InvalidOperationException("Invalid key file.");
}
private static int ReadInt32(byte[] array, int index)
{
return array[index] | array[index + 1] << 8 | array[index + 2] << 16 | array[index + 3] << 24;
}
private static ImmutableArray<byte> CreatePublicKey(byte version, uint exponent, byte[] modulus)
{
using (var ms = new MemoryStream(160))
using (var binaryWriter = new BinaryWriter(ms))
{
binaryWriter.Write(CALG_RSA_SIGN);
binaryWriter.Write(CALG_SHA);
// total size of the rest of the blob (20 - size of RSAPUBKEY)
binaryWriter.Write(modulus.Length + 20);
binaryWriter.Write(PUBLICKEYBLOB);
binaryWriter.Write(version);
binaryWriter.Write((ushort)0x00000000); // reserved
binaryWriter.Write(CALG_RSA_SIGN);
binaryWriter.Write(RSA1);
binaryWriter.Write(modulus.Length << 3);
binaryWriter.Write(exponent);
binaryWriter.Write(modulus);
return ImmutableArray.Create(ms.ToArray());
}
}
}
}