init commit
This commit is contained in:
@@ -0,0 +1,418 @@
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
using Org.BouncyCastle.Utilities.IO;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public class ArmoredInputStream : BaseInputStream
|
||||
{
|
||||
private static readonly byte[] decodingTable;
|
||||
|
||||
private Stream input;
|
||||
|
||||
private bool start = true;
|
||||
|
||||
private int[] outBuf = new int[3];
|
||||
|
||||
private int bufPtr = 3;
|
||||
|
||||
private Crc24 crc = new Crc24();
|
||||
|
||||
private bool crcFound = false;
|
||||
|
||||
private bool hasHeaders = true;
|
||||
|
||||
private string header = null;
|
||||
|
||||
private bool newLineFound = false;
|
||||
|
||||
private bool clearText = false;
|
||||
|
||||
private bool restart = false;
|
||||
|
||||
private IList headerList = Platform.CreateArrayList();
|
||||
|
||||
private int lastC = 0;
|
||||
|
||||
private bool isEndOfStream;
|
||||
|
||||
static ArmoredInputStream()
|
||||
{
|
||||
decodingTable = new byte[128];
|
||||
for (int i = 65; i <= 90; i++)
|
||||
{
|
||||
decodingTable[i] = (byte)(i - 65);
|
||||
}
|
||||
for (int j = 97; j <= 122; j++)
|
||||
{
|
||||
decodingTable[j] = (byte)(j - 97 + 26);
|
||||
}
|
||||
for (int k = 48; k <= 57; k++)
|
||||
{
|
||||
decodingTable[k] = (byte)(k - 48 + 52);
|
||||
}
|
||||
decodingTable[43] = 62;
|
||||
decodingTable[47] = 63;
|
||||
}
|
||||
|
||||
private int Decode(int in0, int in1, int in2, int in3, int[] result)
|
||||
{
|
||||
if (in3 < 0)
|
||||
{
|
||||
throw new EndOfStreamException("unexpected end of file in armored stream.");
|
||||
}
|
||||
int num;
|
||||
int num2;
|
||||
if (in2 == 61)
|
||||
{
|
||||
num = decodingTable[in0] & 0xFF;
|
||||
num2 = decodingTable[in1] & 0xFF;
|
||||
result[2] = ((num << 2) | (num2 >> 4)) & 0xFF;
|
||||
return 2;
|
||||
}
|
||||
int num3;
|
||||
if (in3 == 61)
|
||||
{
|
||||
num = decodingTable[in0];
|
||||
num2 = decodingTable[in1];
|
||||
num3 = decodingTable[in2];
|
||||
result[1] = ((num << 2) | (num2 >> 4)) & 0xFF;
|
||||
result[2] = ((num2 << 4) | (num3 >> 2)) & 0xFF;
|
||||
return 1;
|
||||
}
|
||||
num = decodingTable[in0];
|
||||
num2 = decodingTable[in1];
|
||||
num3 = decodingTable[in2];
|
||||
int num4 = decodingTable[in3];
|
||||
result[0] = ((num << 2) | (num2 >> 4)) & 0xFF;
|
||||
result[1] = ((num2 << 4) | (num3 >> 2)) & 0xFF;
|
||||
result[2] = ((num3 << 6) | num4) & 0xFF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public ArmoredInputStream(Stream input)
|
||||
: this(input, hasHeaders: true)
|
||||
{
|
||||
}
|
||||
|
||||
public ArmoredInputStream(Stream input, bool hasHeaders)
|
||||
{
|
||||
this.input = input;
|
||||
this.hasHeaders = hasHeaders;
|
||||
if (hasHeaders)
|
||||
{
|
||||
ParseHeaders();
|
||||
}
|
||||
start = false;
|
||||
}
|
||||
|
||||
private bool ParseHeaders()
|
||||
{
|
||||
header = null;
|
||||
int num = 0;
|
||||
bool flag = false;
|
||||
headerList = Platform.CreateArrayList();
|
||||
if (restart)
|
||||
{
|
||||
flag = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
int num2;
|
||||
while ((num2 = input.ReadByte()) >= 0)
|
||||
{
|
||||
if (num2 == 45 && (num == 0 || num == 10 || num == 13))
|
||||
{
|
||||
flag = true;
|
||||
break;
|
||||
}
|
||||
num = num2;
|
||||
}
|
||||
}
|
||||
if (flag)
|
||||
{
|
||||
StringBuilder stringBuilder = new StringBuilder("-");
|
||||
bool flag2 = false;
|
||||
bool flag3 = false;
|
||||
if (restart)
|
||||
{
|
||||
stringBuilder.Append('-');
|
||||
}
|
||||
int num2;
|
||||
while ((num2 = input.ReadByte()) >= 0)
|
||||
{
|
||||
if (num == 13 && num2 == 10)
|
||||
{
|
||||
flag3 = true;
|
||||
}
|
||||
if ((flag2 && num != 13 && num2 == 10) || (flag2 && num2 == 13))
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (num2 == 13 || (num != 13 && num2 == 10))
|
||||
{
|
||||
string text = stringBuilder.ToString();
|
||||
if (text.Trim().Length < 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
headerList.Add(text);
|
||||
stringBuilder.Length = 0;
|
||||
}
|
||||
if (num2 != 10 && num2 != 13)
|
||||
{
|
||||
stringBuilder.Append((char)num2);
|
||||
flag2 = false;
|
||||
}
|
||||
else if (num2 == 13 || (num != 13 && num2 == 10))
|
||||
{
|
||||
flag2 = true;
|
||||
}
|
||||
num = num2;
|
||||
}
|
||||
if (flag3)
|
||||
{
|
||||
input.ReadByte();
|
||||
}
|
||||
}
|
||||
if (headerList.Count > 0)
|
||||
{
|
||||
header = (string)headerList[0];
|
||||
}
|
||||
clearText = "-----BEGIN PGP SIGNED MESSAGE-----".Equals(header);
|
||||
newLineFound = true;
|
||||
return flag;
|
||||
}
|
||||
|
||||
public bool IsClearText()
|
||||
{
|
||||
return clearText;
|
||||
}
|
||||
|
||||
public bool IsEndOfStream()
|
||||
{
|
||||
return isEndOfStream;
|
||||
}
|
||||
|
||||
public string GetArmorHeaderLine()
|
||||
{
|
||||
return header;
|
||||
}
|
||||
|
||||
public string[] GetArmorHeaders()
|
||||
{
|
||||
if (headerList.Count <= 1)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
string[] array = new string[headerList.Count - 1];
|
||||
for (int i = 0; i != array.Length; i++)
|
||||
{
|
||||
array[i] = (string)headerList[i + 1];
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
private int ReadIgnoreSpace()
|
||||
{
|
||||
int num;
|
||||
do
|
||||
{
|
||||
num = input.ReadByte();
|
||||
}
|
||||
while (num == 32 || num == 9);
|
||||
return num;
|
||||
}
|
||||
|
||||
private int ReadIgnoreWhitespace()
|
||||
{
|
||||
int num;
|
||||
do
|
||||
{
|
||||
num = input.ReadByte();
|
||||
}
|
||||
while (num == 32 || num == 9 || num == 13 || num == 10);
|
||||
return num;
|
||||
}
|
||||
|
||||
private int ReadByteClearText()
|
||||
{
|
||||
int num = input.ReadByte();
|
||||
if (num == 13 || (num == 10 && lastC != 13))
|
||||
{
|
||||
newLineFound = true;
|
||||
}
|
||||
else if (newLineFound && num == 45)
|
||||
{
|
||||
num = input.ReadByte();
|
||||
if (num == 45)
|
||||
{
|
||||
clearText = false;
|
||||
start = true;
|
||||
restart = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
num = input.ReadByte();
|
||||
}
|
||||
newLineFound = false;
|
||||
}
|
||||
else if (num != 10 && lastC != 13)
|
||||
{
|
||||
newLineFound = false;
|
||||
}
|
||||
lastC = num;
|
||||
if (num < 0)
|
||||
{
|
||||
isEndOfStream = true;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
private int ReadClearText(byte[] buffer, int offset, int count)
|
||||
{
|
||||
int num = offset;
|
||||
try
|
||||
{
|
||||
int num2 = offset + count;
|
||||
while (num < num2)
|
||||
{
|
||||
int num3 = ReadByteClearText();
|
||||
if (num3 != -1)
|
||||
{
|
||||
buffer[num++] = (byte)num3;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
if (num == offset)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
return num - offset;
|
||||
}
|
||||
|
||||
private int DoReadByte()
|
||||
{
|
||||
if (bufPtr > 2 || crcFound)
|
||||
{
|
||||
int num = ReadIgnoreSpace();
|
||||
if (num == 10 || num == 13)
|
||||
{
|
||||
num = ReadIgnoreWhitespace();
|
||||
if (num == 61)
|
||||
{
|
||||
bufPtr = Decode(ReadIgnoreSpace(), ReadIgnoreSpace(), ReadIgnoreSpace(), ReadIgnoreSpace(), outBuf);
|
||||
if (bufPtr != 0)
|
||||
{
|
||||
throw new IOException("no crc found in armored message.");
|
||||
}
|
||||
crcFound = true;
|
||||
int num2 = ((outBuf[0] & 0xFF) << 16) | ((outBuf[1] & 0xFF) << 8) | (outBuf[2] & 0xFF);
|
||||
if (num2 != crc.Value)
|
||||
{
|
||||
throw new IOException("crc check failed in armored message.");
|
||||
}
|
||||
return ReadByte();
|
||||
}
|
||||
if (num == 45)
|
||||
{
|
||||
while ((num = input.ReadByte()) >= 0 && num != 10 && num != 13)
|
||||
{
|
||||
}
|
||||
if (!crcFound)
|
||||
{
|
||||
throw new IOException("crc check not found.");
|
||||
}
|
||||
crcFound = false;
|
||||
start = true;
|
||||
bufPtr = 3;
|
||||
if (num < 0)
|
||||
{
|
||||
isEndOfStream = true;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (num < 0)
|
||||
{
|
||||
isEndOfStream = true;
|
||||
return -1;
|
||||
}
|
||||
bufPtr = Decode(num, ReadIgnoreSpace(), ReadIgnoreSpace(), ReadIgnoreSpace(), outBuf);
|
||||
}
|
||||
return outBuf[bufPtr++];
|
||||
}
|
||||
|
||||
public override int ReadByte()
|
||||
{
|
||||
if (start)
|
||||
{
|
||||
if (hasHeaders)
|
||||
{
|
||||
ParseHeaders();
|
||||
}
|
||||
crc.Reset();
|
||||
start = false;
|
||||
}
|
||||
if (clearText)
|
||||
{
|
||||
return ReadByteClearText();
|
||||
}
|
||||
int num = DoReadByte();
|
||||
crc.Update(num);
|
||||
return num;
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (start && count > 0)
|
||||
{
|
||||
if (hasHeaders)
|
||||
{
|
||||
ParseHeaders();
|
||||
}
|
||||
start = false;
|
||||
}
|
||||
if (clearText)
|
||||
{
|
||||
return ReadClearText(buffer, offset, count);
|
||||
}
|
||||
int num = offset;
|
||||
try
|
||||
{
|
||||
int num2 = offset + count;
|
||||
while (num < num2)
|
||||
{
|
||||
int num3 = DoReadByte();
|
||||
crc.Update(num3);
|
||||
if (num3 != -1)
|
||||
{
|
||||
buffer[num++] = (byte)num3;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
if (num == offset)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
return num - offset;
|
||||
}
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
Platform.Dispose(input);
|
||||
base.Close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
using Org.BouncyCastle.Utilities.IO;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public class ArmoredOutputStream : BaseOutputStream
|
||||
{
|
||||
public static readonly string HeaderVersion = "Version";
|
||||
|
||||
private static readonly byte[] encodingTable = new byte[64]
|
||||
{
|
||||
65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
|
||||
75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
|
||||
85, 86, 87, 88, 89, 90, 97, 98, 99, 100,
|
||||
101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
|
||||
111, 112, 113, 114, 115, 116, 117, 118, 119, 120,
|
||||
121, 122, 48, 49, 50, 51, 52, 53, 54, 55,
|
||||
56, 57, 43, 47
|
||||
};
|
||||
|
||||
private readonly Stream outStream;
|
||||
|
||||
private int[] buf = new int[3];
|
||||
|
||||
private int bufPtr = 0;
|
||||
|
||||
private Crc24 crc = new Crc24();
|
||||
|
||||
private int chunkCount = 0;
|
||||
|
||||
private int lastb;
|
||||
|
||||
private bool start = true;
|
||||
|
||||
private bool clearText = false;
|
||||
|
||||
private bool newLine = false;
|
||||
|
||||
private string type;
|
||||
|
||||
private static readonly string nl = Platform.NewLine;
|
||||
|
||||
private static readonly string headerStart = "-----BEGIN PGP ";
|
||||
|
||||
private static readonly string headerTail = "-----";
|
||||
|
||||
private static readonly string footerStart = "-----END PGP ";
|
||||
|
||||
private static readonly string footerTail = "-----";
|
||||
|
||||
private static readonly string Version = "BCPG C# v" + AssemblyInfo.Version;
|
||||
|
||||
private readonly IDictionary headers;
|
||||
|
||||
private static void Encode(Stream outStream, int[] data, int len)
|
||||
{
|
||||
byte[] array = new byte[4];
|
||||
int num = data[0];
|
||||
array[0] = encodingTable[(num >> 2) & 0x3F];
|
||||
switch (len)
|
||||
{
|
||||
case 1:
|
||||
array[1] = encodingTable[(num << 4) & 0x3F];
|
||||
array[2] = 61;
|
||||
array[3] = 61;
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
int num4 = data[1];
|
||||
array[1] = encodingTable[((num << 4) | (num4 >> 4)) & 0x3F];
|
||||
array[2] = encodingTable[(num4 << 2) & 0x3F];
|
||||
array[3] = 61;
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
int num2 = data[1];
|
||||
int num3 = data[2];
|
||||
array[1] = encodingTable[((num << 4) | (num2 >> 4)) & 0x3F];
|
||||
array[2] = encodingTable[((num2 << 2) | (num3 >> 6)) & 0x3F];
|
||||
array[3] = encodingTable[num3 & 0x3F];
|
||||
break;
|
||||
}
|
||||
}
|
||||
outStream.Write(array, 0, array.Length);
|
||||
}
|
||||
|
||||
public ArmoredOutputStream(Stream outStream)
|
||||
{
|
||||
this.outStream = outStream;
|
||||
headers = Platform.CreateHashtable(1);
|
||||
headers.Add(HeaderVersion, Version);
|
||||
}
|
||||
|
||||
public ArmoredOutputStream(Stream outStream, IDictionary headers)
|
||||
{
|
||||
this.outStream = outStream;
|
||||
this.headers = Platform.CreateHashtable(headers);
|
||||
if (!this.headers.Contains(HeaderVersion))
|
||||
{
|
||||
this.headers.Add(HeaderVersion, Version);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetHeader(string name, string v)
|
||||
{
|
||||
if (v == null)
|
||||
{
|
||||
headers.Remove(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
headers[name] = v;
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetHeaders()
|
||||
{
|
||||
string text = (string)headers[HeaderVersion];
|
||||
headers.Clear();
|
||||
if (text != null)
|
||||
{
|
||||
headers.Add(HeaderVersion, text);
|
||||
}
|
||||
}
|
||||
|
||||
public void BeginClearText(HashAlgorithmTag hashAlgorithm)
|
||||
{
|
||||
string text = hashAlgorithm switch
|
||||
{
|
||||
HashAlgorithmTag.Sha1 => "SHA1",
|
||||
HashAlgorithmTag.Sha256 => "SHA256",
|
||||
HashAlgorithmTag.Sha384 => "SHA384",
|
||||
HashAlgorithmTag.Sha512 => "SHA512",
|
||||
HashAlgorithmTag.MD2 => "MD2",
|
||||
HashAlgorithmTag.MD5 => "MD5",
|
||||
HashAlgorithmTag.RipeMD160 => "RIPEMD160",
|
||||
_ => throw new IOException("unknown hash algorithm tag in beginClearText: " + hashAlgorithm),
|
||||
};
|
||||
DoWrite("-----BEGIN PGP SIGNED MESSAGE-----" + nl);
|
||||
DoWrite("Hash: " + text + nl + nl);
|
||||
clearText = true;
|
||||
newLine = true;
|
||||
lastb = 0;
|
||||
}
|
||||
|
||||
public void EndClearText()
|
||||
{
|
||||
clearText = false;
|
||||
}
|
||||
|
||||
public override void WriteByte(byte b)
|
||||
{
|
||||
if (clearText)
|
||||
{
|
||||
outStream.WriteByte(b);
|
||||
if (newLine)
|
||||
{
|
||||
if (b != 10 || lastb != 13)
|
||||
{
|
||||
newLine = false;
|
||||
}
|
||||
if (b == 45)
|
||||
{
|
||||
outStream.WriteByte(32);
|
||||
outStream.WriteByte(45);
|
||||
}
|
||||
}
|
||||
if (b == 13 || (b == 10 && lastb != 13))
|
||||
{
|
||||
newLine = true;
|
||||
}
|
||||
lastb = b;
|
||||
return;
|
||||
}
|
||||
if (start)
|
||||
{
|
||||
switch ((PacketTag)(((b & 0x40) == 0) ? ((b & 0x3F) >> 2) : (b & 0x3F)))
|
||||
{
|
||||
case PacketTag.PublicKey:
|
||||
type = "PUBLIC KEY BLOCK";
|
||||
break;
|
||||
case PacketTag.SecretKey:
|
||||
type = "PRIVATE KEY BLOCK";
|
||||
break;
|
||||
case PacketTag.Signature:
|
||||
type = "SIGNATURE";
|
||||
break;
|
||||
default:
|
||||
type = "MESSAGE";
|
||||
break;
|
||||
}
|
||||
DoWrite(headerStart + type + headerTail + nl);
|
||||
if (headers.Contains(HeaderVersion))
|
||||
{
|
||||
WriteHeaderEntry(HeaderVersion, (string)headers[HeaderVersion]);
|
||||
}
|
||||
foreach (object header in headers)
|
||||
{
|
||||
DictionaryEntry dictionaryEntry = (DictionaryEntry)header;
|
||||
string text = (string)dictionaryEntry.Key;
|
||||
if (text != HeaderVersion)
|
||||
{
|
||||
string v = (string)dictionaryEntry.Value;
|
||||
WriteHeaderEntry(text, v);
|
||||
}
|
||||
}
|
||||
DoWrite(nl);
|
||||
start = false;
|
||||
}
|
||||
if (bufPtr == 3)
|
||||
{
|
||||
Encode(outStream, buf, bufPtr);
|
||||
bufPtr = 0;
|
||||
if ((++chunkCount & 0xF) == 0)
|
||||
{
|
||||
DoWrite(nl);
|
||||
}
|
||||
}
|
||||
crc.Update(b);
|
||||
buf[bufPtr++] = b & 0xFF;
|
||||
}
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
if (type != null)
|
||||
{
|
||||
DoClose();
|
||||
type = null;
|
||||
start = true;
|
||||
base.Close();
|
||||
}
|
||||
}
|
||||
|
||||
private void DoClose()
|
||||
{
|
||||
if (bufPtr > 0)
|
||||
{
|
||||
Encode(outStream, buf, bufPtr);
|
||||
}
|
||||
DoWrite(nl + '=');
|
||||
int value = crc.Value;
|
||||
buf[0] = (value >> 16) & 0xFF;
|
||||
buf[1] = (value >> 8) & 0xFF;
|
||||
buf[2] = value & 0xFF;
|
||||
Encode(outStream, buf, 3);
|
||||
DoWrite(nl);
|
||||
DoWrite(footerStart);
|
||||
DoWrite(type);
|
||||
DoWrite(footerTail);
|
||||
DoWrite(nl);
|
||||
outStream.Flush();
|
||||
}
|
||||
|
||||
private void WriteHeaderEntry(string name, string v)
|
||||
{
|
||||
DoWrite(name + ": " + v + nl);
|
||||
}
|
||||
|
||||
private void DoWrite(string s)
|
||||
{
|
||||
byte[] array = Strings.ToAsciiByteArray(s);
|
||||
outStream.Write(array, 0, array.Length);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.Attr;
|
||||
|
||||
public class ImageAttrib : UserAttributeSubpacket
|
||||
{
|
||||
public enum Format : byte
|
||||
{
|
||||
Jpeg = 1
|
||||
}
|
||||
|
||||
private static readonly byte[] Zeroes = new byte[12];
|
||||
|
||||
private int hdrLength;
|
||||
|
||||
private int _version;
|
||||
|
||||
private int _encoding;
|
||||
|
||||
private byte[] imageData;
|
||||
|
||||
public virtual int Version => _version;
|
||||
|
||||
public virtual int Encoding => _encoding;
|
||||
|
||||
public ImageAttrib(byte[] data)
|
||||
: this(forceLongLength: false, data)
|
||||
{
|
||||
}
|
||||
|
||||
public ImageAttrib(bool forceLongLength, byte[] data)
|
||||
: base(UserAttributeSubpacketTag.ImageAttribute, forceLongLength, data)
|
||||
{
|
||||
hdrLength = ((data[1] & 0xFF) << 8) | (data[0] & 0xFF);
|
||||
_version = data[2] & 0xFF;
|
||||
_encoding = data[3] & 0xFF;
|
||||
imageData = new byte[data.Length - hdrLength];
|
||||
Array.Copy(data, hdrLength, imageData, 0, imageData.Length);
|
||||
}
|
||||
|
||||
public ImageAttrib(Format imageType, byte[] imageData)
|
||||
: this(ToByteArray(imageType, imageData))
|
||||
{
|
||||
}
|
||||
|
||||
private static byte[] ToByteArray(Format imageType, byte[] imageData)
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
memoryStream.WriteByte(16);
|
||||
memoryStream.WriteByte(0);
|
||||
memoryStream.WriteByte(1);
|
||||
memoryStream.WriteByte((byte)imageType);
|
||||
memoryStream.Write(Zeroes, 0, Zeroes.Length);
|
||||
memoryStream.Write(imageData, 0, imageData.Length);
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
|
||||
public virtual byte[] GetImageData()
|
||||
{
|
||||
return imageData;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,309 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
using Org.BouncyCastle.Utilities.IO;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public class BcpgInputStream : BaseInputStream
|
||||
{
|
||||
private class PartialInputStream : BaseInputStream
|
||||
{
|
||||
private BcpgInputStream m_in;
|
||||
|
||||
private bool partial;
|
||||
|
||||
private int dataLength;
|
||||
|
||||
internal PartialInputStream(BcpgInputStream bcpgIn, bool partial, int dataLength)
|
||||
{
|
||||
m_in = bcpgIn;
|
||||
this.partial = partial;
|
||||
this.dataLength = dataLength;
|
||||
}
|
||||
|
||||
public override int ReadByte()
|
||||
{
|
||||
do
|
||||
{
|
||||
if (dataLength != 0)
|
||||
{
|
||||
int num = m_in.ReadByte();
|
||||
if (num < 0)
|
||||
{
|
||||
throw new EndOfStreamException("Premature end of stream in PartialInputStream");
|
||||
}
|
||||
dataLength--;
|
||||
return num;
|
||||
}
|
||||
}
|
||||
while (partial && ReadPartialDataLength() >= 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (dataLength != 0)
|
||||
{
|
||||
int count2 = ((dataLength > count || dataLength < 0) ? count : dataLength);
|
||||
int num = m_in.Read(buffer, offset, count2);
|
||||
if (num < 1)
|
||||
{
|
||||
throw new EndOfStreamException("Premature end of stream in PartialInputStream");
|
||||
}
|
||||
dataLength -= num;
|
||||
return num;
|
||||
}
|
||||
}
|
||||
while (partial && ReadPartialDataLength() >= 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int ReadPartialDataLength()
|
||||
{
|
||||
int num = m_in.ReadByte();
|
||||
if (num < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
partial = false;
|
||||
if (num < 192)
|
||||
{
|
||||
dataLength = num;
|
||||
}
|
||||
else if (num <= 223)
|
||||
{
|
||||
dataLength = (num - 192 << 8) + m_in.ReadByte() + 192;
|
||||
}
|
||||
else if (num == 255)
|
||||
{
|
||||
dataLength = (m_in.ReadByte() << 24) | (m_in.ReadByte() << 16) | (m_in.ReadByte() << 8) | m_in.ReadByte();
|
||||
}
|
||||
else
|
||||
{
|
||||
partial = true;
|
||||
dataLength = 1 << (num & 0x1F);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private Stream m_in;
|
||||
|
||||
private bool next = false;
|
||||
|
||||
private int nextB;
|
||||
|
||||
internal static BcpgInputStream Wrap(Stream inStr)
|
||||
{
|
||||
if (inStr is BcpgInputStream)
|
||||
{
|
||||
return (BcpgInputStream)inStr;
|
||||
}
|
||||
return new BcpgInputStream(inStr);
|
||||
}
|
||||
|
||||
private BcpgInputStream(Stream inputStream)
|
||||
{
|
||||
m_in = inputStream;
|
||||
}
|
||||
|
||||
public override int ReadByte()
|
||||
{
|
||||
if (next)
|
||||
{
|
||||
next = false;
|
||||
return nextB;
|
||||
}
|
||||
return m_in.ReadByte();
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (!next)
|
||||
{
|
||||
return m_in.Read(buffer, offset, count);
|
||||
}
|
||||
if (nextB < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (buffer == null)
|
||||
{
|
||||
throw new ArgumentNullException("buffer");
|
||||
}
|
||||
buffer[offset] = (byte)nextB;
|
||||
next = false;
|
||||
return 1;
|
||||
}
|
||||
|
||||
public byte[] ReadAll()
|
||||
{
|
||||
return Streams.ReadAll(this);
|
||||
}
|
||||
|
||||
public void ReadFully(byte[] buffer, int off, int len)
|
||||
{
|
||||
if (Streams.ReadFully(this, buffer, off, len) < len)
|
||||
{
|
||||
throw new EndOfStreamException();
|
||||
}
|
||||
}
|
||||
|
||||
public void ReadFully(byte[] buffer)
|
||||
{
|
||||
ReadFully(buffer, 0, buffer.Length);
|
||||
}
|
||||
|
||||
public PacketTag NextPacketTag()
|
||||
{
|
||||
if (!next)
|
||||
{
|
||||
try
|
||||
{
|
||||
nextB = m_in.ReadByte();
|
||||
}
|
||||
catch (EndOfStreamException)
|
||||
{
|
||||
nextB = -1;
|
||||
}
|
||||
next = true;
|
||||
}
|
||||
if (nextB < 0)
|
||||
{
|
||||
return (PacketTag)nextB;
|
||||
}
|
||||
int num = nextB & 0x3F;
|
||||
if ((nextB & 0x40) == 0)
|
||||
{
|
||||
num >>= 2;
|
||||
}
|
||||
return (PacketTag)num;
|
||||
}
|
||||
|
||||
public Packet ReadPacket()
|
||||
{
|
||||
int num = ReadByte();
|
||||
if (num < 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if ((num & 0x80) == 0)
|
||||
{
|
||||
throw new IOException("invalid header encountered");
|
||||
}
|
||||
bool flag = (num & 0x40) != 0;
|
||||
PacketTag packetTag = PacketTag.Reserved;
|
||||
int num2 = 0;
|
||||
bool flag2 = false;
|
||||
if (flag)
|
||||
{
|
||||
packetTag = (PacketTag)(num & 0x3F);
|
||||
int num3 = ReadByte();
|
||||
if (num3 < 192)
|
||||
{
|
||||
num2 = num3;
|
||||
}
|
||||
else if (num3 <= 223)
|
||||
{
|
||||
int num4 = m_in.ReadByte();
|
||||
num2 = (num3 - 192 << 8) + num4 + 192;
|
||||
}
|
||||
else if (num3 == 255)
|
||||
{
|
||||
num2 = (m_in.ReadByte() << 24) | (m_in.ReadByte() << 16) | (m_in.ReadByte() << 8) | m_in.ReadByte();
|
||||
}
|
||||
else
|
||||
{
|
||||
flag2 = true;
|
||||
num2 = 1 << (num3 & 0x1F);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int num5 = num & 3;
|
||||
packetTag = (PacketTag)((num & 0x3F) >> 2);
|
||||
switch (num5)
|
||||
{
|
||||
case 0:
|
||||
num2 = ReadByte();
|
||||
break;
|
||||
case 1:
|
||||
num2 = (ReadByte() << 8) | ReadByte();
|
||||
break;
|
||||
case 2:
|
||||
num2 = (ReadByte() << 24) | (ReadByte() << 16) | (ReadByte() << 8) | ReadByte();
|
||||
break;
|
||||
case 3:
|
||||
flag2 = true;
|
||||
break;
|
||||
default:
|
||||
throw new IOException("unknown length type encountered");
|
||||
}
|
||||
}
|
||||
BcpgInputStream bcpgIn;
|
||||
if (num2 == 0 && flag2)
|
||||
{
|
||||
bcpgIn = this;
|
||||
}
|
||||
else
|
||||
{
|
||||
PartialInputStream inputStream = new PartialInputStream(this, flag2, num2);
|
||||
bcpgIn = new BcpgInputStream(inputStream);
|
||||
}
|
||||
switch (packetTag)
|
||||
{
|
||||
case PacketTag.Reserved:
|
||||
return new InputStreamPacket(bcpgIn);
|
||||
case PacketTag.PublicKeyEncryptedSession:
|
||||
return new PublicKeyEncSessionPacket(bcpgIn);
|
||||
case PacketTag.Signature:
|
||||
return new SignaturePacket(bcpgIn);
|
||||
case PacketTag.SymmetricKeyEncryptedSessionKey:
|
||||
return new SymmetricKeyEncSessionPacket(bcpgIn);
|
||||
case PacketTag.OnePassSignature:
|
||||
return new OnePassSignaturePacket(bcpgIn);
|
||||
case PacketTag.SecretKey:
|
||||
return new SecretKeyPacket(bcpgIn);
|
||||
case PacketTag.PublicKey:
|
||||
return new PublicKeyPacket(bcpgIn);
|
||||
case PacketTag.SecretSubkey:
|
||||
return new SecretSubkeyPacket(bcpgIn);
|
||||
case PacketTag.CompressedData:
|
||||
return new CompressedDataPacket(bcpgIn);
|
||||
case PacketTag.SymmetricKeyEncrypted:
|
||||
return new SymmetricEncDataPacket(bcpgIn);
|
||||
case PacketTag.Marker:
|
||||
return new MarkerPacket(bcpgIn);
|
||||
case PacketTag.LiteralData:
|
||||
return new LiteralDataPacket(bcpgIn);
|
||||
case PacketTag.Trust:
|
||||
return new TrustPacket(bcpgIn);
|
||||
case PacketTag.UserId:
|
||||
return new UserIdPacket(bcpgIn);
|
||||
case PacketTag.UserAttribute:
|
||||
return new UserAttributePacket(bcpgIn);
|
||||
case PacketTag.PublicSubkey:
|
||||
return new PublicSubkeyPacket(bcpgIn);
|
||||
case PacketTag.SymmetricEncryptedIntegrityProtected:
|
||||
return new SymmetricEncIntegrityPacket(bcpgIn);
|
||||
case PacketTag.ModificationDetectionCode:
|
||||
return new ModDetectionCodePacket(bcpgIn);
|
||||
case PacketTag.Experimental1:
|
||||
case PacketTag.Experimental2:
|
||||
case PacketTag.Experimental3:
|
||||
case PacketTag.Experimental4:
|
||||
return new ExperimentalPacket(packetTag, bcpgIn);
|
||||
default:
|
||||
throw new IOException("unknown packet type encountered: " + packetTag);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
Platform.Dispose(m_in);
|
||||
base.Close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public abstract class BcpgObject
|
||||
{
|
||||
public virtual byte[] GetEncoded()
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
BcpgOutputStream bcpgOutputStream = new BcpgOutputStream(memoryStream);
|
||||
bcpgOutputStream.WriteObject(this);
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
|
||||
public abstract void Encode(BcpgOutputStream bcpgOut);
|
||||
}
|
||||
@@ -0,0 +1,314 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
using Org.BouncyCastle.Utilities.IO;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public class BcpgOutputStream : BaseOutputStream
|
||||
{
|
||||
private const int BufferSizePower = 16;
|
||||
|
||||
private Stream outStr;
|
||||
|
||||
private byte[] partialBuffer;
|
||||
|
||||
private int partialBufferLength;
|
||||
|
||||
private int partialPower;
|
||||
|
||||
private int partialOffset;
|
||||
|
||||
internal static BcpgOutputStream Wrap(Stream outStr)
|
||||
{
|
||||
if (outStr is BcpgOutputStream)
|
||||
{
|
||||
return (BcpgOutputStream)outStr;
|
||||
}
|
||||
return new BcpgOutputStream(outStr);
|
||||
}
|
||||
|
||||
public BcpgOutputStream(Stream outStr)
|
||||
{
|
||||
if (outStr == null)
|
||||
{
|
||||
throw new ArgumentNullException("outStr");
|
||||
}
|
||||
this.outStr = outStr;
|
||||
}
|
||||
|
||||
public BcpgOutputStream(Stream outStr, PacketTag tag)
|
||||
{
|
||||
if (outStr == null)
|
||||
{
|
||||
throw new ArgumentNullException("outStr");
|
||||
}
|
||||
this.outStr = outStr;
|
||||
WriteHeader(tag, oldPackets: true, partial: true, 0L);
|
||||
}
|
||||
|
||||
public BcpgOutputStream(Stream outStr, PacketTag tag, long length, bool oldFormat)
|
||||
{
|
||||
if (outStr == null)
|
||||
{
|
||||
throw new ArgumentNullException("outStr");
|
||||
}
|
||||
this.outStr = outStr;
|
||||
if (length > uint.MaxValue)
|
||||
{
|
||||
WriteHeader(tag, oldPackets: false, partial: true, 0L);
|
||||
partialBufferLength = 65536;
|
||||
partialBuffer = new byte[partialBufferLength];
|
||||
partialPower = 16;
|
||||
partialOffset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteHeader(tag, oldFormat, partial: false, length);
|
||||
}
|
||||
}
|
||||
|
||||
public BcpgOutputStream(Stream outStr, PacketTag tag, long length)
|
||||
{
|
||||
if (outStr == null)
|
||||
{
|
||||
throw new ArgumentNullException("outStr");
|
||||
}
|
||||
this.outStr = outStr;
|
||||
WriteHeader(tag, oldPackets: false, partial: false, length);
|
||||
}
|
||||
|
||||
public BcpgOutputStream(Stream outStr, PacketTag tag, byte[] buffer)
|
||||
{
|
||||
if (outStr == null)
|
||||
{
|
||||
throw new ArgumentNullException("outStr");
|
||||
}
|
||||
this.outStr = outStr;
|
||||
WriteHeader(tag, oldPackets: false, partial: true, 0L);
|
||||
partialBuffer = buffer;
|
||||
uint num = (uint)partialBuffer.Length;
|
||||
partialPower = 0;
|
||||
while (num != 1)
|
||||
{
|
||||
num >>= 1;
|
||||
partialPower++;
|
||||
}
|
||||
if (partialPower > 30)
|
||||
{
|
||||
throw new IOException("Buffer cannot be greater than 2^30 in length.");
|
||||
}
|
||||
partialBufferLength = 1 << partialPower;
|
||||
partialOffset = 0;
|
||||
}
|
||||
|
||||
private void WriteNewPacketLength(long bodyLen)
|
||||
{
|
||||
if (bodyLen < 192)
|
||||
{
|
||||
outStr.WriteByte((byte)bodyLen);
|
||||
}
|
||||
else if (bodyLen <= 8383)
|
||||
{
|
||||
bodyLen -= 192;
|
||||
outStr.WriteByte((byte)(((bodyLen >> 8) & 0xFF) + 192));
|
||||
outStr.WriteByte((byte)bodyLen);
|
||||
}
|
||||
else
|
||||
{
|
||||
outStr.WriteByte(byte.MaxValue);
|
||||
outStr.WriteByte((byte)(bodyLen >> 24));
|
||||
outStr.WriteByte((byte)(bodyLen >> 16));
|
||||
outStr.WriteByte((byte)(bodyLen >> 8));
|
||||
outStr.WriteByte((byte)bodyLen);
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteHeader(PacketTag tag, bool oldPackets, bool partial, long bodyLen)
|
||||
{
|
||||
int num = 128;
|
||||
if (partialBuffer != null)
|
||||
{
|
||||
PartialFlush(isLast: true);
|
||||
partialBuffer = null;
|
||||
}
|
||||
if (oldPackets)
|
||||
{
|
||||
num |= (int)tag << 2;
|
||||
if (partial)
|
||||
{
|
||||
WriteByte((byte)(num | 3));
|
||||
}
|
||||
else if (bodyLen <= 255)
|
||||
{
|
||||
WriteByte((byte)num);
|
||||
WriteByte((byte)bodyLen);
|
||||
}
|
||||
else if (bodyLen <= 65535)
|
||||
{
|
||||
WriteByte((byte)(num | 1));
|
||||
WriteByte((byte)(bodyLen >> 8));
|
||||
WriteByte((byte)bodyLen);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteByte((byte)(num | 2));
|
||||
WriteByte((byte)(bodyLen >> 24));
|
||||
WriteByte((byte)(bodyLen >> 16));
|
||||
WriteByte((byte)(bodyLen >> 8));
|
||||
WriteByte((byte)bodyLen);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
num |= (int)((PacketTag)64 | tag);
|
||||
WriteByte((byte)num);
|
||||
if (partial)
|
||||
{
|
||||
partialOffset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteNewPacketLength(bodyLen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void PartialFlush(bool isLast)
|
||||
{
|
||||
if (isLast)
|
||||
{
|
||||
WriteNewPacketLength(partialOffset);
|
||||
outStr.Write(partialBuffer, 0, partialOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
outStr.WriteByte((byte)(0xE0 | partialPower));
|
||||
outStr.Write(partialBuffer, 0, partialBufferLength);
|
||||
}
|
||||
partialOffset = 0;
|
||||
}
|
||||
|
||||
private void WritePartial(byte b)
|
||||
{
|
||||
if (partialOffset == partialBufferLength)
|
||||
{
|
||||
PartialFlush(isLast: false);
|
||||
}
|
||||
partialBuffer[partialOffset++] = b;
|
||||
}
|
||||
|
||||
private void WritePartial(byte[] buffer, int off, int len)
|
||||
{
|
||||
if (partialOffset == partialBufferLength)
|
||||
{
|
||||
PartialFlush(isLast: false);
|
||||
}
|
||||
if (len <= partialBufferLength - partialOffset)
|
||||
{
|
||||
Array.Copy(buffer, off, partialBuffer, partialOffset, len);
|
||||
partialOffset += len;
|
||||
return;
|
||||
}
|
||||
int num = partialBufferLength - partialOffset;
|
||||
Array.Copy(buffer, off, partialBuffer, partialOffset, num);
|
||||
off += num;
|
||||
len -= num;
|
||||
PartialFlush(isLast: false);
|
||||
while (len > partialBufferLength)
|
||||
{
|
||||
Array.Copy(buffer, off, partialBuffer, 0, partialBufferLength);
|
||||
off += partialBufferLength;
|
||||
len -= partialBufferLength;
|
||||
PartialFlush(isLast: false);
|
||||
}
|
||||
Array.Copy(buffer, off, partialBuffer, 0, len);
|
||||
partialOffset += len;
|
||||
}
|
||||
|
||||
public override void WriteByte(byte value)
|
||||
{
|
||||
if (partialBuffer != null)
|
||||
{
|
||||
WritePartial(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
outStr.WriteByte(value);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (partialBuffer != null)
|
||||
{
|
||||
WritePartial(buffer, offset, count);
|
||||
}
|
||||
else
|
||||
{
|
||||
outStr.Write(buffer, offset, count);
|
||||
}
|
||||
}
|
||||
|
||||
internal virtual void WriteShort(short n)
|
||||
{
|
||||
Write((byte)(n >> 8), (byte)n);
|
||||
}
|
||||
|
||||
internal virtual void WriteInt(int n)
|
||||
{
|
||||
Write((byte)(n >> 24), (byte)(n >> 16), (byte)(n >> 8), (byte)n);
|
||||
}
|
||||
|
||||
internal virtual void WriteLong(long n)
|
||||
{
|
||||
Write((byte)(n >> 56), (byte)(n >> 48), (byte)(n >> 40), (byte)(n >> 32), (byte)(n >> 24), (byte)(n >> 16), (byte)(n >> 8), (byte)n);
|
||||
}
|
||||
|
||||
public void WritePacket(ContainedPacket p)
|
||||
{
|
||||
p.Encode(this);
|
||||
}
|
||||
|
||||
internal void WritePacket(PacketTag tag, byte[] body, bool oldFormat)
|
||||
{
|
||||
WriteHeader(tag, oldFormat, partial: false, body.Length);
|
||||
Write(body);
|
||||
}
|
||||
|
||||
public void WriteObject(BcpgObject bcpgObject)
|
||||
{
|
||||
bcpgObject.Encode(this);
|
||||
}
|
||||
|
||||
public void WriteObjects(params BcpgObject[] v)
|
||||
{
|
||||
foreach (BcpgObject bcpgObject in v)
|
||||
{
|
||||
bcpgObject.Encode(this);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
outStr.Flush();
|
||||
}
|
||||
|
||||
public void Finish()
|
||||
{
|
||||
if (partialBuffer != null)
|
||||
{
|
||||
PartialFlush(isLast: true);
|
||||
Array.Clear(partialBuffer, 0, partialBuffer.Length);
|
||||
partialBuffer = null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
Finish();
|
||||
outStr.Flush();
|
||||
Platform.Dispose(outStr);
|
||||
base.Close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public class CompressedDataPacket : InputStreamPacket
|
||||
{
|
||||
private readonly CompressionAlgorithmTag algorithm;
|
||||
|
||||
public CompressionAlgorithmTag Algorithm => algorithm;
|
||||
|
||||
internal CompressedDataPacket(BcpgInputStream bcpgIn)
|
||||
: base(bcpgIn)
|
||||
{
|
||||
algorithm = (CompressionAlgorithmTag)bcpgIn.ReadByte();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public enum CompressionAlgorithmTag
|
||||
{
|
||||
Uncompressed,
|
||||
Zip,
|
||||
ZLib,
|
||||
BZip2
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public abstract class ContainedPacket : Packet
|
||||
{
|
||||
public byte[] GetEncoded()
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
BcpgOutputStream bcpgOutputStream = new BcpgOutputStream(memoryStream);
|
||||
bcpgOutputStream.WritePacket(this);
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
|
||||
public abstract void Encode(BcpgOutputStream bcpgOut);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public class Crc24
|
||||
{
|
||||
private const int Crc24Init = 11994318;
|
||||
|
||||
private const int Crc24Poly = 25578747;
|
||||
|
||||
private int crc = 11994318;
|
||||
|
||||
public int Value => crc;
|
||||
|
||||
public void Update(int b)
|
||||
{
|
||||
crc ^= b << 16;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
crc <<= 1;
|
||||
if ((crc & 0x1000000) != 0)
|
||||
{
|
||||
crc ^= 25578747;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("Use 'Value' property instead")]
|
||||
public int GetValue()
|
||||
{
|
||||
return crc;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
crc = 11994318;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using Org.BouncyCastle.Math;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public class DsaPublicBcpgKey : BcpgObject, IBcpgKey
|
||||
{
|
||||
private readonly MPInteger p;
|
||||
|
||||
private readonly MPInteger q;
|
||||
|
||||
private readonly MPInteger g;
|
||||
|
||||
private readonly MPInteger y;
|
||||
|
||||
public string Format => "PGP";
|
||||
|
||||
public BigInteger G => g.Value;
|
||||
|
||||
public BigInteger P => p.Value;
|
||||
|
||||
public BigInteger Q => q.Value;
|
||||
|
||||
public BigInteger Y => y.Value;
|
||||
|
||||
public DsaPublicBcpgKey(BcpgInputStream bcpgIn)
|
||||
{
|
||||
p = new MPInteger(bcpgIn);
|
||||
q = new MPInteger(bcpgIn);
|
||||
g = new MPInteger(bcpgIn);
|
||||
y = new MPInteger(bcpgIn);
|
||||
}
|
||||
|
||||
public DsaPublicBcpgKey(BigInteger p, BigInteger q, BigInteger g, BigInteger y)
|
||||
{
|
||||
this.p = new MPInteger(p);
|
||||
this.q = new MPInteger(q);
|
||||
this.g = new MPInteger(g);
|
||||
this.y = new MPInteger(y);
|
||||
}
|
||||
|
||||
public override byte[] GetEncoded()
|
||||
{
|
||||
try
|
||||
{
|
||||
return base.GetEncoded();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Encode(BcpgOutputStream bcpgOut)
|
||||
{
|
||||
bcpgOut.WriteObjects(p, q, g, y);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using Org.BouncyCastle.Math;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public class DsaSecretBcpgKey : BcpgObject, IBcpgKey
|
||||
{
|
||||
internal MPInteger x;
|
||||
|
||||
public string Format => "PGP";
|
||||
|
||||
public BigInteger X => x.Value;
|
||||
|
||||
public DsaSecretBcpgKey(BcpgInputStream bcpgIn)
|
||||
{
|
||||
x = new MPInteger(bcpgIn);
|
||||
}
|
||||
|
||||
public DsaSecretBcpgKey(BigInteger x)
|
||||
{
|
||||
this.x = new MPInteger(x);
|
||||
}
|
||||
|
||||
public override byte[] GetEncoded()
|
||||
{
|
||||
try
|
||||
{
|
||||
return base.GetEncoded();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Encode(BcpgOutputStream bcpgOut)
|
||||
{
|
||||
bcpgOut.WriteObject(x);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
using System;
|
||||
using Org.BouncyCastle.Asn1;
|
||||
using Org.BouncyCastle.Math.EC;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public class ECDHPublicBcpgKey : ECPublicBcpgKey
|
||||
{
|
||||
private byte reserved;
|
||||
|
||||
private HashAlgorithmTag hashFunctionId;
|
||||
|
||||
private SymmetricKeyAlgorithmTag symAlgorithmId;
|
||||
|
||||
public virtual byte Reserved => reserved;
|
||||
|
||||
public virtual HashAlgorithmTag HashAlgorithm => hashFunctionId;
|
||||
|
||||
public virtual SymmetricKeyAlgorithmTag SymmetricKeyAlgorithm => symAlgorithmId;
|
||||
|
||||
public ECDHPublicBcpgKey(BcpgInputStream bcpgIn)
|
||||
: base(bcpgIn)
|
||||
{
|
||||
int num = bcpgIn.ReadByte();
|
||||
byte[] array = new byte[num];
|
||||
if (array.Length != 3)
|
||||
{
|
||||
throw new InvalidOperationException("kdf parameters size of 3 expected.");
|
||||
}
|
||||
bcpgIn.ReadFully(array);
|
||||
reserved = array[0];
|
||||
hashFunctionId = (HashAlgorithmTag)array[1];
|
||||
symAlgorithmId = (SymmetricKeyAlgorithmTag)array[2];
|
||||
VerifyHashAlgorithm();
|
||||
VerifySymmetricKeyAlgorithm();
|
||||
}
|
||||
|
||||
public ECDHPublicBcpgKey(DerObjectIdentifier oid, ECPoint point, HashAlgorithmTag hashAlgorithm, SymmetricKeyAlgorithmTag symmetricKeyAlgorithm)
|
||||
: base(oid, point)
|
||||
{
|
||||
reserved = 1;
|
||||
hashFunctionId = hashAlgorithm;
|
||||
symAlgorithmId = symmetricKeyAlgorithm;
|
||||
VerifyHashAlgorithm();
|
||||
VerifySymmetricKeyAlgorithm();
|
||||
}
|
||||
|
||||
public override void Encode(BcpgOutputStream bcpgOut)
|
||||
{
|
||||
base.Encode(bcpgOut);
|
||||
bcpgOut.WriteByte(3);
|
||||
bcpgOut.WriteByte(reserved);
|
||||
bcpgOut.WriteByte((byte)hashFunctionId);
|
||||
bcpgOut.WriteByte((byte)symAlgorithmId);
|
||||
}
|
||||
|
||||
private void VerifyHashAlgorithm()
|
||||
{
|
||||
switch (hashFunctionId)
|
||||
{
|
||||
case HashAlgorithmTag.Sha256:
|
||||
case HashAlgorithmTag.Sha384:
|
||||
case HashAlgorithmTag.Sha512:
|
||||
return;
|
||||
}
|
||||
throw new InvalidOperationException("Hash algorithm must be SHA-256 or stronger.");
|
||||
}
|
||||
|
||||
private void VerifySymmetricKeyAlgorithm()
|
||||
{
|
||||
switch (symAlgorithmId)
|
||||
{
|
||||
case SymmetricKeyAlgorithmTag.Aes128:
|
||||
case SymmetricKeyAlgorithmTag.Aes192:
|
||||
case SymmetricKeyAlgorithmTag.Aes256:
|
||||
return;
|
||||
}
|
||||
throw new InvalidOperationException("Symmetric key algorithm must be AES-128 or stronger.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using Org.BouncyCastle.Asn1;
|
||||
using Org.BouncyCastle.Math;
|
||||
using Org.BouncyCastle.Math.EC;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public class ECDsaPublicBcpgKey : ECPublicBcpgKey
|
||||
{
|
||||
protected internal ECDsaPublicBcpgKey(BcpgInputStream bcpgIn)
|
||||
: base(bcpgIn)
|
||||
{
|
||||
}
|
||||
|
||||
public ECDsaPublicBcpgKey(DerObjectIdentifier oid, ECPoint point)
|
||||
: base(oid, point)
|
||||
{
|
||||
}
|
||||
|
||||
public ECDsaPublicBcpgKey(DerObjectIdentifier oid, BigInteger encodedPoint)
|
||||
: base(oid, encodedPoint)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Asn1;
|
||||
using Org.BouncyCastle.Math;
|
||||
using Org.BouncyCastle.Math.EC;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public abstract class ECPublicBcpgKey : BcpgObject, IBcpgKey
|
||||
{
|
||||
internal DerObjectIdentifier oid;
|
||||
|
||||
internal BigInteger point;
|
||||
|
||||
public string Format => "PGP";
|
||||
|
||||
public virtual BigInteger EncodedPoint => point;
|
||||
|
||||
public virtual DerObjectIdentifier CurveOid => oid;
|
||||
|
||||
protected ECPublicBcpgKey(BcpgInputStream bcpgIn)
|
||||
{
|
||||
oid = DerObjectIdentifier.GetInstance(Asn1Object.FromByteArray(ReadBytesOfEncodedLength(bcpgIn)));
|
||||
point = new MPInteger(bcpgIn).Value;
|
||||
}
|
||||
|
||||
protected ECPublicBcpgKey(DerObjectIdentifier oid, ECPoint point)
|
||||
{
|
||||
this.point = new BigInteger(1, point.GetEncoded(compressed: false));
|
||||
this.oid = oid;
|
||||
}
|
||||
|
||||
protected ECPublicBcpgKey(DerObjectIdentifier oid, BigInteger encodedPoint)
|
||||
{
|
||||
point = encodedPoint;
|
||||
this.oid = oid;
|
||||
}
|
||||
|
||||
public override byte[] GetEncoded()
|
||||
{
|
||||
try
|
||||
{
|
||||
return base.GetEncoded();
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Encode(BcpgOutputStream bcpgOut)
|
||||
{
|
||||
byte[] encoded = oid.GetEncoded();
|
||||
bcpgOut.Write(encoded, 1, encoded.Length - 1);
|
||||
MPInteger bcpgObject = new MPInteger(point);
|
||||
bcpgOut.WriteObject(bcpgObject);
|
||||
}
|
||||
|
||||
protected static byte[] ReadBytesOfEncodedLength(BcpgInputStream bcpgIn)
|
||||
{
|
||||
int num = bcpgIn.ReadByte();
|
||||
if (num == 0 || num == 255)
|
||||
{
|
||||
throw new IOException("future extensions not yet implemented.");
|
||||
}
|
||||
byte[] array = new byte[num + 2];
|
||||
bcpgIn.ReadFully(array, 2, array.Length - 2);
|
||||
array[0] = 6;
|
||||
array[1] = (byte)num;
|
||||
return array;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using Org.BouncyCastle.Math;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public class ECSecretBcpgKey : BcpgObject, IBcpgKey
|
||||
{
|
||||
internal MPInteger x;
|
||||
|
||||
public string Format => "PGP";
|
||||
|
||||
public virtual BigInteger X => x.Value;
|
||||
|
||||
public ECSecretBcpgKey(BcpgInputStream bcpgIn)
|
||||
{
|
||||
x = new MPInteger(bcpgIn);
|
||||
}
|
||||
|
||||
public ECSecretBcpgKey(BigInteger x)
|
||||
{
|
||||
this.x = new MPInteger(x);
|
||||
}
|
||||
|
||||
public override byte[] GetEncoded()
|
||||
{
|
||||
try
|
||||
{
|
||||
return base.GetEncoded();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Encode(BcpgOutputStream bcpgOut)
|
||||
{
|
||||
bcpgOut.WriteObject(x);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using Org.BouncyCastle.Math;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public class ElGamalPublicBcpgKey : BcpgObject, IBcpgKey
|
||||
{
|
||||
internal MPInteger p;
|
||||
|
||||
internal MPInteger g;
|
||||
|
||||
internal MPInteger y;
|
||||
|
||||
public string Format => "PGP";
|
||||
|
||||
public BigInteger P => p.Value;
|
||||
|
||||
public BigInteger G => g.Value;
|
||||
|
||||
public BigInteger Y => y.Value;
|
||||
|
||||
public ElGamalPublicBcpgKey(BcpgInputStream bcpgIn)
|
||||
{
|
||||
p = new MPInteger(bcpgIn);
|
||||
g = new MPInteger(bcpgIn);
|
||||
y = new MPInteger(bcpgIn);
|
||||
}
|
||||
|
||||
public ElGamalPublicBcpgKey(BigInteger p, BigInteger g, BigInteger y)
|
||||
{
|
||||
this.p = new MPInteger(p);
|
||||
this.g = new MPInteger(g);
|
||||
this.y = new MPInteger(y);
|
||||
}
|
||||
|
||||
public override byte[] GetEncoded()
|
||||
{
|
||||
try
|
||||
{
|
||||
return base.GetEncoded();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Encode(BcpgOutputStream bcpgOut)
|
||||
{
|
||||
bcpgOut.WriteObjects(p, g, y);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using Org.BouncyCastle.Math;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public class ElGamalSecretBcpgKey : BcpgObject, IBcpgKey
|
||||
{
|
||||
internal MPInteger x;
|
||||
|
||||
public string Format => "PGP";
|
||||
|
||||
public BigInteger X => x.Value;
|
||||
|
||||
public ElGamalSecretBcpgKey(BcpgInputStream bcpgIn)
|
||||
{
|
||||
x = new MPInteger(bcpgIn);
|
||||
}
|
||||
|
||||
public ElGamalSecretBcpgKey(BigInteger x)
|
||||
{
|
||||
this.x = new MPInteger(x);
|
||||
}
|
||||
|
||||
public override byte[] GetEncoded()
|
||||
{
|
||||
try
|
||||
{
|
||||
return base.GetEncoded();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Encode(BcpgOutputStream bcpgOut)
|
||||
{
|
||||
bcpgOut.WriteObject(x);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public class ExperimentalPacket : ContainedPacket
|
||||
{
|
||||
private readonly PacketTag tag;
|
||||
|
||||
private readonly byte[] contents;
|
||||
|
||||
public PacketTag Tag => tag;
|
||||
|
||||
internal ExperimentalPacket(PacketTag tag, BcpgInputStream bcpgIn)
|
||||
{
|
||||
this.tag = tag;
|
||||
contents = bcpgIn.ReadAll();
|
||||
}
|
||||
|
||||
public byte[] GetContents()
|
||||
{
|
||||
return (byte[])contents.Clone();
|
||||
}
|
||||
|
||||
public override void Encode(BcpgOutputStream bcpgOut)
|
||||
{
|
||||
bcpgOut.WritePacket(tag, contents, oldFormat: true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public enum HashAlgorithmTag
|
||||
{
|
||||
MD5 = 1,
|
||||
Sha1,
|
||||
RipeMD160,
|
||||
DoubleSha,
|
||||
MD2,
|
||||
Tiger192,
|
||||
Haval5pass160,
|
||||
Sha256,
|
||||
Sha384,
|
||||
Sha512,
|
||||
Sha224
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public interface IBcpgKey
|
||||
{
|
||||
string Format { get; }
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public class InputStreamPacket : Packet
|
||||
{
|
||||
private readonly BcpgInputStream bcpgIn;
|
||||
|
||||
public InputStreamPacket(BcpgInputStream bcpgIn)
|
||||
{
|
||||
this.bcpgIn = bcpgIn;
|
||||
}
|
||||
|
||||
public BcpgInputStream GetInputStream()
|
||||
{
|
||||
return bcpgIn;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public class LiteralDataPacket : InputStreamPacket
|
||||
{
|
||||
private int format;
|
||||
|
||||
private byte[] fileName;
|
||||
|
||||
private long modDate;
|
||||
|
||||
public int Format => format;
|
||||
|
||||
public long ModificationTime => modDate;
|
||||
|
||||
public string FileName => Strings.FromUtf8ByteArray(fileName);
|
||||
|
||||
internal LiteralDataPacket(BcpgInputStream bcpgIn)
|
||||
: base(bcpgIn)
|
||||
{
|
||||
format = bcpgIn.ReadByte();
|
||||
int num = bcpgIn.ReadByte();
|
||||
fileName = new byte[num];
|
||||
for (int i = 0; i != num; i++)
|
||||
{
|
||||
int num2 = bcpgIn.ReadByte();
|
||||
if (num2 < 0)
|
||||
{
|
||||
throw new IOException("literal data truncated in header");
|
||||
}
|
||||
fileName[i] = (byte)num2;
|
||||
}
|
||||
modDate = (long)(uint)((bcpgIn.ReadByte() << 24) | (bcpgIn.ReadByte() << 16) | (bcpgIn.ReadByte() << 8) | bcpgIn.ReadByte()) * 1000L;
|
||||
}
|
||||
|
||||
public byte[] GetRawFileName()
|
||||
{
|
||||
return Arrays.Clone(fileName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using Org.BouncyCastle.Math;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public class MPInteger : BcpgObject
|
||||
{
|
||||
private readonly BigInteger val;
|
||||
|
||||
public BigInteger Value => val;
|
||||
|
||||
public MPInteger(BcpgInputStream bcpgIn)
|
||||
{
|
||||
if (bcpgIn == null)
|
||||
{
|
||||
throw new ArgumentNullException("bcpgIn");
|
||||
}
|
||||
int num = (bcpgIn.ReadByte() << 8) | bcpgIn.ReadByte();
|
||||
byte[] array = new byte[(num + 7) / 8];
|
||||
bcpgIn.ReadFully(array);
|
||||
val = new BigInteger(1, array);
|
||||
}
|
||||
|
||||
public MPInteger(BigInteger val)
|
||||
{
|
||||
if (val == null)
|
||||
{
|
||||
throw new ArgumentNullException("val");
|
||||
}
|
||||
if (val.SignValue < 0)
|
||||
{
|
||||
throw new ArgumentException("Values must be positive", "val");
|
||||
}
|
||||
this.val = val;
|
||||
}
|
||||
|
||||
public override void Encode(BcpgOutputStream bcpgOut)
|
||||
{
|
||||
bcpgOut.WriteShort((short)val.BitLength);
|
||||
bcpgOut.Write(val.ToByteArrayUnsigned());
|
||||
}
|
||||
|
||||
internal static void Encode(BcpgOutputStream bcpgOut, BigInteger val)
|
||||
{
|
||||
bcpgOut.WriteShort((short)val.BitLength);
|
||||
bcpgOut.Write(val.ToByteArrayUnsigned());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public class MarkerPacket : ContainedPacket
|
||||
{
|
||||
private byte[] marker = new byte[3] { 80, 71, 80 };
|
||||
|
||||
public MarkerPacket(BcpgInputStream bcpgIn)
|
||||
{
|
||||
bcpgIn.ReadFully(marker);
|
||||
}
|
||||
|
||||
public override void Encode(BcpgOutputStream bcpgOut)
|
||||
{
|
||||
bcpgOut.WritePacket(PacketTag.Marker, marker, oldFormat: true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public class ModDetectionCodePacket : ContainedPacket
|
||||
{
|
||||
private readonly byte[] digest;
|
||||
|
||||
internal ModDetectionCodePacket(BcpgInputStream bcpgIn)
|
||||
{
|
||||
if (bcpgIn == null)
|
||||
{
|
||||
throw new ArgumentNullException("bcpgIn");
|
||||
}
|
||||
digest = new byte[20];
|
||||
bcpgIn.ReadFully(digest);
|
||||
}
|
||||
|
||||
public ModDetectionCodePacket(byte[] digest)
|
||||
{
|
||||
if (digest == null)
|
||||
{
|
||||
throw new ArgumentNullException("digest");
|
||||
}
|
||||
this.digest = (byte[])digest.Clone();
|
||||
}
|
||||
|
||||
public byte[] GetDigest()
|
||||
{
|
||||
return (byte[])digest.Clone();
|
||||
}
|
||||
|
||||
public override void Encode(BcpgOutputStream bcpgOut)
|
||||
{
|
||||
bcpgOut.WritePacket(PacketTag.ModificationDetectionCode, digest, oldFormat: false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public class OnePassSignaturePacket : ContainedPacket
|
||||
{
|
||||
private int version;
|
||||
|
||||
private int sigType;
|
||||
|
||||
private HashAlgorithmTag hashAlgorithm;
|
||||
|
||||
private PublicKeyAlgorithmTag keyAlgorithm;
|
||||
|
||||
private long keyId;
|
||||
|
||||
private int nested;
|
||||
|
||||
public int SignatureType => sigType;
|
||||
|
||||
public PublicKeyAlgorithmTag KeyAlgorithm => keyAlgorithm;
|
||||
|
||||
public HashAlgorithmTag HashAlgorithm => hashAlgorithm;
|
||||
|
||||
public long KeyId => keyId;
|
||||
|
||||
internal OnePassSignaturePacket(BcpgInputStream bcpgIn)
|
||||
{
|
||||
version = bcpgIn.ReadByte();
|
||||
sigType = bcpgIn.ReadByte();
|
||||
hashAlgorithm = (HashAlgorithmTag)bcpgIn.ReadByte();
|
||||
keyAlgorithm = (PublicKeyAlgorithmTag)bcpgIn.ReadByte();
|
||||
keyId |= (long)bcpgIn.ReadByte() << 56;
|
||||
keyId |= (long)bcpgIn.ReadByte() << 48;
|
||||
keyId |= (long)bcpgIn.ReadByte() << 40;
|
||||
keyId |= (long)bcpgIn.ReadByte() << 32;
|
||||
keyId |= (long)bcpgIn.ReadByte() << 24;
|
||||
keyId |= (long)bcpgIn.ReadByte() << 16;
|
||||
keyId |= (long)bcpgIn.ReadByte() << 8;
|
||||
keyId |= (uint)bcpgIn.ReadByte();
|
||||
nested = bcpgIn.ReadByte();
|
||||
}
|
||||
|
||||
public OnePassSignaturePacket(int sigType, HashAlgorithmTag hashAlgorithm, PublicKeyAlgorithmTag keyAlgorithm, long keyId, bool isNested)
|
||||
{
|
||||
version = 3;
|
||||
this.sigType = sigType;
|
||||
this.hashAlgorithm = hashAlgorithm;
|
||||
this.keyAlgorithm = keyAlgorithm;
|
||||
this.keyId = keyId;
|
||||
nested = ((!isNested) ? 1 : 0);
|
||||
}
|
||||
|
||||
public override void Encode(BcpgOutputStream bcpgOut)
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
BcpgOutputStream bcpgOutputStream = new BcpgOutputStream(memoryStream);
|
||||
bcpgOutputStream.Write((byte)version, (byte)sigType, (byte)hashAlgorithm, (byte)keyAlgorithm);
|
||||
bcpgOutputStream.WriteLong(keyId);
|
||||
bcpgOutputStream.WriteByte((byte)nested);
|
||||
bcpgOut.WritePacket(PacketTag.OnePassSignature, memoryStream.ToArray(), oldFormat: true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public interface IStreamGenerator
|
||||
{
|
||||
void Close();
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Apache.Bzip2;
|
||||
using Org.BouncyCastle.Utilities.Zlib;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpCompressedData : PgpObject
|
||||
{
|
||||
private readonly CompressedDataPacket data;
|
||||
|
||||
public CompressionAlgorithmTag Algorithm => data.Algorithm;
|
||||
|
||||
public PgpCompressedData(BcpgInputStream bcpgInput)
|
||||
{
|
||||
data = (CompressedDataPacket)bcpgInput.ReadPacket();
|
||||
}
|
||||
|
||||
public Stream GetInputStream()
|
||||
{
|
||||
return data.GetInputStream();
|
||||
}
|
||||
|
||||
public Stream GetDataStream()
|
||||
{
|
||||
return Algorithm switch
|
||||
{
|
||||
CompressionAlgorithmTag.Uncompressed => GetInputStream(),
|
||||
CompressionAlgorithmTag.Zip => new ZInputStream(GetInputStream(), nowrap: true),
|
||||
CompressionAlgorithmTag.ZLib => new ZInputStream(GetInputStream()),
|
||||
CompressionAlgorithmTag.BZip2 => new CBZip2InputStream(GetInputStream()),
|
||||
_ => throw new PgpException("can't recognise compression algorithm: " + Algorithm),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Apache.Bzip2;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
using Org.BouncyCastle.Utilities.Zlib;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpCompressedDataGenerator : IStreamGenerator
|
||||
{
|
||||
private class SafeCBZip2OutputStream : CBZip2OutputStream
|
||||
{
|
||||
public SafeCBZip2OutputStream(Stream output)
|
||||
: base(output)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
Finish();
|
||||
}
|
||||
}
|
||||
|
||||
private class SafeZOutputStream : ZOutputStream
|
||||
{
|
||||
public SafeZOutputStream(Stream output, int level, bool nowrap)
|
||||
: base(output, level, nowrap)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
Finish();
|
||||
End();
|
||||
}
|
||||
}
|
||||
|
||||
private readonly CompressionAlgorithmTag algorithm;
|
||||
|
||||
private readonly int compression;
|
||||
|
||||
private Stream dOut;
|
||||
|
||||
private BcpgOutputStream pkOut;
|
||||
|
||||
public PgpCompressedDataGenerator(CompressionAlgorithmTag algorithm)
|
||||
: this(algorithm, -1)
|
||||
{
|
||||
}
|
||||
|
||||
public PgpCompressedDataGenerator(CompressionAlgorithmTag algorithm, int compression)
|
||||
{
|
||||
switch (algorithm)
|
||||
{
|
||||
default:
|
||||
throw new ArgumentException("unknown compression algorithm", "algorithm");
|
||||
case CompressionAlgorithmTag.Uncompressed:
|
||||
case CompressionAlgorithmTag.Zip:
|
||||
case CompressionAlgorithmTag.ZLib:
|
||||
case CompressionAlgorithmTag.BZip2:
|
||||
switch (compression)
|
||||
{
|
||||
default:
|
||||
throw new ArgumentException("unknown compression level: " + compression);
|
||||
case -1:
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
this.algorithm = algorithm;
|
||||
this.compression = compression;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public Stream Open(Stream outStr)
|
||||
{
|
||||
if (dOut != null)
|
||||
{
|
||||
throw new InvalidOperationException("generator already in open state");
|
||||
}
|
||||
if (outStr == null)
|
||||
{
|
||||
throw new ArgumentNullException("outStr");
|
||||
}
|
||||
pkOut = new BcpgOutputStream(outStr, PacketTag.CompressedData);
|
||||
doOpen();
|
||||
return new WrappedGeneratorStream(this, dOut);
|
||||
}
|
||||
|
||||
public Stream Open(Stream outStr, byte[] buffer)
|
||||
{
|
||||
if (dOut != null)
|
||||
{
|
||||
throw new InvalidOperationException("generator already in open state");
|
||||
}
|
||||
if (outStr == null)
|
||||
{
|
||||
throw new ArgumentNullException("outStr");
|
||||
}
|
||||
if (buffer == null)
|
||||
{
|
||||
throw new ArgumentNullException("buffer");
|
||||
}
|
||||
pkOut = new BcpgOutputStream(outStr, PacketTag.CompressedData, buffer);
|
||||
doOpen();
|
||||
return new WrappedGeneratorStream(this, dOut);
|
||||
}
|
||||
|
||||
private void doOpen()
|
||||
{
|
||||
pkOut.WriteByte((byte)algorithm);
|
||||
switch (algorithm)
|
||||
{
|
||||
case CompressionAlgorithmTag.Uncompressed:
|
||||
dOut = pkOut;
|
||||
break;
|
||||
case CompressionAlgorithmTag.Zip:
|
||||
dOut = new SafeZOutputStream(pkOut, compression, nowrap: true);
|
||||
break;
|
||||
case CompressionAlgorithmTag.ZLib:
|
||||
dOut = new SafeZOutputStream(pkOut, compression, nowrap: false);
|
||||
break;
|
||||
case CompressionAlgorithmTag.BZip2:
|
||||
dOut = new SafeCBZip2OutputStream(pkOut);
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
if (dOut != null)
|
||||
{
|
||||
if (dOut != pkOut)
|
||||
{
|
||||
Platform.Dispose(dOut);
|
||||
}
|
||||
dOut = null;
|
||||
pkOut.Finish();
|
||||
pkOut.Flush();
|
||||
pkOut = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
[Serializable]
|
||||
public class PgpDataValidationException : PgpException
|
||||
{
|
||||
public PgpDataValidationException()
|
||||
{
|
||||
}
|
||||
|
||||
public PgpDataValidationException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public PgpDataValidationException(string message, Exception exception)
|
||||
: base(message, exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.IO;
|
||||
using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
using Org.BouncyCastle.Utilities.IO;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public abstract class PgpEncryptedData
|
||||
{
|
||||
internal class TruncatedStream : BaseInputStream
|
||||
{
|
||||
private const int LookAheadSize = 22;
|
||||
|
||||
private const int LookAheadBufSize = 512;
|
||||
|
||||
private const int LookAheadBufLimit = 490;
|
||||
|
||||
private readonly Stream inStr;
|
||||
|
||||
private readonly byte[] lookAhead = new byte[512];
|
||||
|
||||
private int bufStart;
|
||||
|
||||
private int bufEnd;
|
||||
|
||||
internal TruncatedStream(Stream inStr)
|
||||
{
|
||||
int num = Streams.ReadFully(inStr, lookAhead, 0, lookAhead.Length);
|
||||
if (num < 22)
|
||||
{
|
||||
throw new EndOfStreamException();
|
||||
}
|
||||
this.inStr = inStr;
|
||||
bufStart = 0;
|
||||
bufEnd = num - 22;
|
||||
}
|
||||
|
||||
private int FillBuffer()
|
||||
{
|
||||
if (bufEnd < 490)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
Array.Copy(lookAhead, 490, lookAhead, 0, 22);
|
||||
bufEnd = Streams.ReadFully(inStr, lookAhead, 22, 490);
|
||||
bufStart = 0;
|
||||
return bufEnd;
|
||||
}
|
||||
|
||||
public override int ReadByte()
|
||||
{
|
||||
if (bufStart < bufEnd)
|
||||
{
|
||||
return lookAhead[bufStart++];
|
||||
}
|
||||
if (FillBuffer() < 1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return lookAhead[bufStart++];
|
||||
}
|
||||
|
||||
public override int Read(byte[] buf, int off, int len)
|
||||
{
|
||||
int num = bufEnd - bufStart;
|
||||
int num2 = off;
|
||||
while (len > num)
|
||||
{
|
||||
Array.Copy(lookAhead, bufStart, buf, num2, num);
|
||||
bufStart += num;
|
||||
num2 += num;
|
||||
len -= num;
|
||||
if ((num = FillBuffer()) < 1)
|
||||
{
|
||||
return num2 - off;
|
||||
}
|
||||
}
|
||||
Array.Copy(lookAhead, bufStart, buf, num2, len);
|
||||
bufStart += len;
|
||||
return num2 + len - off;
|
||||
}
|
||||
|
||||
internal byte[] GetLookAhead()
|
||||
{
|
||||
byte[] array = new byte[22];
|
||||
Array.Copy(lookAhead, bufStart, array, 0, 22);
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
internal InputStreamPacket encData;
|
||||
|
||||
internal Stream encStream;
|
||||
|
||||
internal TruncatedStream truncStream;
|
||||
|
||||
internal PgpEncryptedData(InputStreamPacket encData)
|
||||
{
|
||||
this.encData = encData;
|
||||
}
|
||||
|
||||
public virtual Stream GetInputStream()
|
||||
{
|
||||
return encData.GetInputStream();
|
||||
}
|
||||
|
||||
public bool IsIntegrityProtected()
|
||||
{
|
||||
return encData is SymmetricEncIntegrityPacket;
|
||||
}
|
||||
|
||||
public bool Verify()
|
||||
{
|
||||
if (!IsIntegrityProtected())
|
||||
{
|
||||
throw new PgpException("data not integrity protected.");
|
||||
}
|
||||
DigestStream digestStream = (DigestStream)encStream;
|
||||
while (encStream.ReadByte() >= 0)
|
||||
{
|
||||
}
|
||||
byte[] lookAhead = truncStream.GetLookAhead();
|
||||
IDigest digest = digestStream.ReadDigest();
|
||||
digest.BlockUpdate(lookAhead, 0, 2);
|
||||
byte[] array = DigestUtilities.DoFinal(digest);
|
||||
byte[] array2 = new byte[array.Length];
|
||||
Array.Copy(lookAhead, 2, array2, 0, array2.Length);
|
||||
return Arrays.ConstantTimeAreEqual(array, array2);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,423 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.IO;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Math;
|
||||
using Org.BouncyCastle.Math.EC;
|
||||
using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpEncryptedDataGenerator : IStreamGenerator
|
||||
{
|
||||
private abstract class EncMethod : ContainedPacket
|
||||
{
|
||||
protected byte[] sessionInfo;
|
||||
|
||||
protected SymmetricKeyAlgorithmTag encAlgorithm;
|
||||
|
||||
protected KeyParameter key;
|
||||
|
||||
public abstract void AddSessionInfo(byte[] si, SecureRandom random);
|
||||
}
|
||||
|
||||
private class PbeMethod : EncMethod
|
||||
{
|
||||
private S2k s2k;
|
||||
|
||||
internal PbeMethod(SymmetricKeyAlgorithmTag encAlgorithm, S2k s2k, KeyParameter key)
|
||||
{
|
||||
base.encAlgorithm = encAlgorithm;
|
||||
this.s2k = s2k;
|
||||
base.key = key;
|
||||
}
|
||||
|
||||
public KeyParameter GetKey()
|
||||
{
|
||||
return key;
|
||||
}
|
||||
|
||||
public override void AddSessionInfo(byte[] si, SecureRandom random)
|
||||
{
|
||||
string symmetricCipherName = PgpUtilities.GetSymmetricCipherName(encAlgorithm);
|
||||
IBufferedCipher cipher = CipherUtilities.GetCipher(symmetricCipherName + "/CFB/NoPadding");
|
||||
byte[] iv = new byte[cipher.GetBlockSize()];
|
||||
cipher.Init(forEncryption: true, new ParametersWithRandom(new ParametersWithIV(key, iv), random));
|
||||
sessionInfo = cipher.DoFinal(si, 0, si.Length - 2);
|
||||
}
|
||||
|
||||
public override void Encode(BcpgOutputStream pOut)
|
||||
{
|
||||
SymmetricKeyEncSessionPacket p = new SymmetricKeyEncSessionPacket(encAlgorithm, s2k, sessionInfo);
|
||||
pOut.WritePacket(p);
|
||||
}
|
||||
}
|
||||
|
||||
private class PubMethod : EncMethod
|
||||
{
|
||||
internal PgpPublicKey pubKey;
|
||||
|
||||
internal byte[][] data;
|
||||
|
||||
internal PubMethod(PgpPublicKey pubKey)
|
||||
{
|
||||
this.pubKey = pubKey;
|
||||
}
|
||||
|
||||
public override void AddSessionInfo(byte[] sessionInfo, SecureRandom random)
|
||||
{
|
||||
byte[] encryptedSessionInfo = EncryptSessionInfo(sessionInfo, random);
|
||||
data = ProcessSessionInfo(encryptedSessionInfo);
|
||||
}
|
||||
|
||||
private byte[] EncryptSessionInfo(byte[] sessionInfo, SecureRandom random)
|
||||
{
|
||||
if (pubKey.Algorithm != PublicKeyAlgorithmTag.EC)
|
||||
{
|
||||
IBufferedCipher cipher;
|
||||
switch (pubKey.Algorithm)
|
||||
{
|
||||
case PublicKeyAlgorithmTag.RsaGeneral:
|
||||
case PublicKeyAlgorithmTag.RsaEncrypt:
|
||||
cipher = CipherUtilities.GetCipher("RSA//PKCS1Padding");
|
||||
break;
|
||||
case PublicKeyAlgorithmTag.ElGamalEncrypt:
|
||||
case PublicKeyAlgorithmTag.ElGamalGeneral:
|
||||
cipher = CipherUtilities.GetCipher("ElGamal/ECB/PKCS1Padding");
|
||||
break;
|
||||
case PublicKeyAlgorithmTag.Dsa:
|
||||
throw new PgpException("Can't use DSA for encryption.");
|
||||
case PublicKeyAlgorithmTag.ECDsa:
|
||||
throw new PgpException("Can't use ECDSA for encryption.");
|
||||
default:
|
||||
throw new PgpException("unknown asymmetric algorithm: " + pubKey.Algorithm);
|
||||
}
|
||||
AsymmetricKeyParameter parameters = pubKey.GetKey();
|
||||
cipher.Init(forEncryption: true, new ParametersWithRandom(parameters, random));
|
||||
return cipher.DoFinal(sessionInfo);
|
||||
}
|
||||
ECDHPublicBcpgKey eCDHPublicBcpgKey = (ECDHPublicBcpgKey)pubKey.PublicKeyPacket.Key;
|
||||
IAsymmetricCipherKeyPairGenerator keyPairGenerator = GeneratorUtilities.GetKeyPairGenerator("ECDH");
|
||||
keyPairGenerator.Init(new ECKeyGenerationParameters(eCDHPublicBcpgKey.CurveOid, random));
|
||||
AsymmetricCipherKeyPair asymmetricCipherKeyPair = keyPairGenerator.GenerateKeyPair();
|
||||
ECPrivateKeyParameters eCPrivateKeyParameters = (ECPrivateKeyParameters)asymmetricCipherKeyPair.Private;
|
||||
ECPublicKeyParameters eCPublicKeyParameters = (ECPublicKeyParameters)asymmetricCipherKeyPair.Public;
|
||||
ECPublicKeyParameters eCPublicKeyParameters2 = (ECPublicKeyParameters)pubKey.GetKey();
|
||||
ECPoint s = eCPublicKeyParameters2.Q.Multiply(eCPrivateKeyParameters.D).Normalize();
|
||||
KeyParameter parameters2 = new KeyParameter(Rfc6637Utilities.CreateKey(pubKey.PublicKeyPacket, s));
|
||||
IWrapper wrapper = PgpUtilities.CreateWrapper(eCDHPublicBcpgKey.SymmetricKeyAlgorithm);
|
||||
wrapper.Init(forWrapping: true, new ParametersWithRandom(parameters2, random));
|
||||
byte[] array = PgpPad.PadSessionData(sessionInfo);
|
||||
byte[] array2 = wrapper.Wrap(array, 0, array.Length);
|
||||
byte[] encoded = new MPInteger(new BigInteger(1, eCPublicKeyParameters.Q.GetEncoded(compressed: false))).GetEncoded();
|
||||
byte[] array3 = new byte[encoded.Length + 1 + array2.Length];
|
||||
Array.Copy(encoded, 0, array3, 0, encoded.Length);
|
||||
array3[encoded.Length] = (byte)array2.Length;
|
||||
Array.Copy(array2, 0, array3, encoded.Length + 1, array2.Length);
|
||||
return array3;
|
||||
}
|
||||
|
||||
private byte[][] ProcessSessionInfo(byte[] encryptedSessionInfo)
|
||||
{
|
||||
switch (pubKey.Algorithm)
|
||||
{
|
||||
case PublicKeyAlgorithmTag.RsaGeneral:
|
||||
case PublicKeyAlgorithmTag.RsaEncrypt:
|
||||
return new byte[1][] { ConvertToEncodedMpi(encryptedSessionInfo) };
|
||||
case PublicKeyAlgorithmTag.ElGamalEncrypt:
|
||||
case PublicKeyAlgorithmTag.ElGamalGeneral:
|
||||
{
|
||||
int num = encryptedSessionInfo.Length / 2;
|
||||
byte[] array = new byte[num];
|
||||
byte[] array2 = new byte[num];
|
||||
Array.Copy(encryptedSessionInfo, 0, array, 0, num);
|
||||
Array.Copy(encryptedSessionInfo, num, array2, 0, num);
|
||||
return new byte[2][]
|
||||
{
|
||||
ConvertToEncodedMpi(array),
|
||||
ConvertToEncodedMpi(array2)
|
||||
};
|
||||
}
|
||||
case PublicKeyAlgorithmTag.EC:
|
||||
return new byte[1][] { encryptedSessionInfo };
|
||||
default:
|
||||
throw new PgpException("unknown asymmetric algorithm: " + pubKey.Algorithm);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] ConvertToEncodedMpi(byte[] encryptedSessionInfo)
|
||||
{
|
||||
try
|
||||
{
|
||||
return new MPInteger(new BigInteger(1, encryptedSessionInfo)).GetEncoded();
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
throw new PgpException("Invalid MPI encoding: " + ex.Message, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Encode(BcpgOutputStream pOut)
|
||||
{
|
||||
PublicKeyEncSessionPacket p = new PublicKeyEncSessionPacket(pubKey.KeyId, pubKey.Algorithm, data);
|
||||
pOut.WritePacket(p);
|
||||
}
|
||||
}
|
||||
|
||||
private BcpgOutputStream pOut;
|
||||
|
||||
private CipherStream cOut;
|
||||
|
||||
private IBufferedCipher c;
|
||||
|
||||
private bool withIntegrityPacket;
|
||||
|
||||
private bool oldFormat;
|
||||
|
||||
private DigestStream digestOut;
|
||||
|
||||
private readonly IList methods = Platform.CreateArrayList();
|
||||
|
||||
private readonly SymmetricKeyAlgorithmTag defAlgorithm;
|
||||
|
||||
private readonly SecureRandom rand;
|
||||
|
||||
public PgpEncryptedDataGenerator(SymmetricKeyAlgorithmTag encAlgorithm)
|
||||
{
|
||||
defAlgorithm = encAlgorithm;
|
||||
rand = new SecureRandom();
|
||||
}
|
||||
|
||||
public PgpEncryptedDataGenerator(SymmetricKeyAlgorithmTag encAlgorithm, bool withIntegrityPacket)
|
||||
{
|
||||
defAlgorithm = encAlgorithm;
|
||||
this.withIntegrityPacket = withIntegrityPacket;
|
||||
rand = new SecureRandom();
|
||||
}
|
||||
|
||||
public PgpEncryptedDataGenerator(SymmetricKeyAlgorithmTag encAlgorithm, SecureRandom rand)
|
||||
{
|
||||
defAlgorithm = encAlgorithm;
|
||||
this.rand = rand;
|
||||
}
|
||||
|
||||
public PgpEncryptedDataGenerator(SymmetricKeyAlgorithmTag encAlgorithm, bool withIntegrityPacket, SecureRandom rand)
|
||||
{
|
||||
defAlgorithm = encAlgorithm;
|
||||
this.rand = rand;
|
||||
this.withIntegrityPacket = withIntegrityPacket;
|
||||
}
|
||||
|
||||
public PgpEncryptedDataGenerator(SymmetricKeyAlgorithmTag encAlgorithm, SecureRandom rand, bool oldFormat)
|
||||
{
|
||||
defAlgorithm = encAlgorithm;
|
||||
this.rand = rand;
|
||||
this.oldFormat = oldFormat;
|
||||
}
|
||||
|
||||
[Obsolete("Use version that takes an explicit s2kDigest parameter")]
|
||||
public void AddMethod(char[] passPhrase)
|
||||
{
|
||||
AddMethod(passPhrase, HashAlgorithmTag.Sha1);
|
||||
}
|
||||
|
||||
public void AddMethod(char[] passPhrase, HashAlgorithmTag s2kDigest)
|
||||
{
|
||||
DoAddMethod(PgpUtilities.EncodePassPhrase(passPhrase, utf8: false), clearPassPhrase: true, s2kDigest);
|
||||
}
|
||||
|
||||
public void AddMethodUtf8(char[] passPhrase, HashAlgorithmTag s2kDigest)
|
||||
{
|
||||
DoAddMethod(PgpUtilities.EncodePassPhrase(passPhrase, utf8: true), clearPassPhrase: true, s2kDigest);
|
||||
}
|
||||
|
||||
public void AddMethodRaw(byte[] rawPassPhrase, HashAlgorithmTag s2kDigest)
|
||||
{
|
||||
DoAddMethod(rawPassPhrase, clearPassPhrase: false, s2kDigest);
|
||||
}
|
||||
|
||||
internal void DoAddMethod(byte[] rawPassPhrase, bool clearPassPhrase, HashAlgorithmTag s2kDigest)
|
||||
{
|
||||
S2k s2k = PgpUtilities.GenerateS2k(s2kDigest, 96, rand);
|
||||
methods.Add(new PbeMethod(defAlgorithm, s2k, PgpUtilities.DoMakeKeyFromPassPhrase(defAlgorithm, s2k, rawPassPhrase, clearPassPhrase)));
|
||||
}
|
||||
|
||||
public void AddMethod(PgpPublicKey key)
|
||||
{
|
||||
if (!key.IsEncryptionKey)
|
||||
{
|
||||
throw new ArgumentException("passed in key not an encryption key!");
|
||||
}
|
||||
methods.Add(new PubMethod(key));
|
||||
}
|
||||
|
||||
private void AddCheckSum(byte[] sessionInfo)
|
||||
{
|
||||
int num = 0;
|
||||
for (int i = 1; i < sessionInfo.Length - 2; i++)
|
||||
{
|
||||
num += sessionInfo[i];
|
||||
}
|
||||
sessionInfo[^2] = (byte)(num >> 8);
|
||||
sessionInfo[^1] = (byte)num;
|
||||
}
|
||||
|
||||
private byte[] CreateSessionInfo(SymmetricKeyAlgorithmTag algorithm, KeyParameter key)
|
||||
{
|
||||
byte[] key2 = key.GetKey();
|
||||
byte[] array = new byte[key2.Length + 3];
|
||||
array[0] = (byte)algorithm;
|
||||
key2.CopyTo(array, 1);
|
||||
AddCheckSum(array);
|
||||
return array;
|
||||
}
|
||||
|
||||
private Stream Open(Stream outStr, long length, byte[] buffer)
|
||||
{
|
||||
if (cOut != null)
|
||||
{
|
||||
throw new InvalidOperationException("generator already in open state");
|
||||
}
|
||||
if (methods.Count == 0)
|
||||
{
|
||||
throw new InvalidOperationException("No encryption methods specified");
|
||||
}
|
||||
if (outStr == null)
|
||||
{
|
||||
throw new ArgumentNullException("outStr");
|
||||
}
|
||||
pOut = new BcpgOutputStream(outStr);
|
||||
KeyParameter keyParameter;
|
||||
if (methods.Count == 1)
|
||||
{
|
||||
if (methods[0] is PbeMethod)
|
||||
{
|
||||
PbeMethod pbeMethod = (PbeMethod)methods[0];
|
||||
keyParameter = pbeMethod.GetKey();
|
||||
}
|
||||
else
|
||||
{
|
||||
keyParameter = PgpUtilities.MakeRandomKey(defAlgorithm, rand);
|
||||
byte[] si = CreateSessionInfo(defAlgorithm, keyParameter);
|
||||
PubMethod pubMethod = (PubMethod)methods[0];
|
||||
try
|
||||
{
|
||||
pubMethod.AddSessionInfo(si, rand);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw new PgpException("exception encrypting session key", exception);
|
||||
}
|
||||
}
|
||||
pOut.WritePacket((ContainedPacket)methods[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
keyParameter = PgpUtilities.MakeRandomKey(defAlgorithm, rand);
|
||||
byte[] si2 = CreateSessionInfo(defAlgorithm, keyParameter);
|
||||
for (int i = 0; i != methods.Count; i++)
|
||||
{
|
||||
EncMethod encMethod = (EncMethod)methods[i];
|
||||
try
|
||||
{
|
||||
encMethod.AddSessionInfo(si2, rand);
|
||||
}
|
||||
catch (Exception exception2)
|
||||
{
|
||||
throw new PgpException("exception encrypting session key", exception2);
|
||||
}
|
||||
pOut.WritePacket(encMethod);
|
||||
}
|
||||
}
|
||||
string symmetricCipherName = PgpUtilities.GetSymmetricCipherName(defAlgorithm);
|
||||
if (symmetricCipherName == null)
|
||||
{
|
||||
throw new PgpException("null cipher specified");
|
||||
}
|
||||
try
|
||||
{
|
||||
symmetricCipherName = ((!withIntegrityPacket) ? (symmetricCipherName + "/OpenPGPCFB/NoPadding") : (symmetricCipherName + "/CFB/NoPadding"));
|
||||
c = CipherUtilities.GetCipher(symmetricCipherName);
|
||||
byte[] iv = new byte[c.GetBlockSize()];
|
||||
c.Init(forEncryption: true, new ParametersWithRandom(new ParametersWithIV(keyParameter, iv), rand));
|
||||
if (buffer == null)
|
||||
{
|
||||
if (withIntegrityPacket)
|
||||
{
|
||||
pOut = new BcpgOutputStream(outStr, PacketTag.SymmetricEncryptedIntegrityProtected, length + c.GetBlockSize() + 2 + 1 + 22);
|
||||
pOut.WriteByte(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
pOut = new BcpgOutputStream(outStr, PacketTag.SymmetricKeyEncrypted, length + c.GetBlockSize() + 2, oldFormat);
|
||||
}
|
||||
}
|
||||
else if (withIntegrityPacket)
|
||||
{
|
||||
pOut = new BcpgOutputStream(outStr, PacketTag.SymmetricEncryptedIntegrityProtected, buffer);
|
||||
pOut.WriteByte(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
pOut = new BcpgOutputStream(outStr, PacketTag.SymmetricKeyEncrypted, buffer);
|
||||
}
|
||||
int blockSize = c.GetBlockSize();
|
||||
byte[] array = new byte[blockSize + 2];
|
||||
rand.NextBytes(array, 0, blockSize);
|
||||
Array.Copy(array, array.Length - 4, array, array.Length - 2, 2);
|
||||
Stream stream = (cOut = new CipherStream(pOut, null, c));
|
||||
if (withIntegrityPacket)
|
||||
{
|
||||
string digestName = PgpUtilities.GetDigestName(HashAlgorithmTag.Sha1);
|
||||
IDigest digest = DigestUtilities.GetDigest(digestName);
|
||||
stream = (digestOut = new DigestStream(stream, null, digest));
|
||||
}
|
||||
stream.Write(array, 0, array.Length);
|
||||
return new WrappedGeneratorStream(this, stream);
|
||||
}
|
||||
catch (Exception exception3)
|
||||
{
|
||||
throw new PgpException("Exception creating cipher", exception3);
|
||||
}
|
||||
}
|
||||
|
||||
public Stream Open(Stream outStr, long length)
|
||||
{
|
||||
return Open(outStr, length, null);
|
||||
}
|
||||
|
||||
public Stream Open(Stream outStr, byte[] buffer)
|
||||
{
|
||||
return Open(outStr, 0L, buffer);
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
if (cOut != null)
|
||||
{
|
||||
if (digestOut != null)
|
||||
{
|
||||
BcpgOutputStream bcpgOutputStream = new BcpgOutputStream(digestOut, PacketTag.ModificationDetectionCode, 20L);
|
||||
bcpgOutputStream.Flush();
|
||||
digestOut.Flush();
|
||||
byte[] array = DigestUtilities.DoFinal(digestOut.WriteDigest());
|
||||
cOut.Write(array, 0, array.Length);
|
||||
}
|
||||
cOut.Flush();
|
||||
try
|
||||
{
|
||||
pOut.Write(c.DoFinal());
|
||||
pOut.Finish();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new IOException(ex.Message, ex);
|
||||
}
|
||||
cOut = null;
|
||||
pOut = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
using Org.BouncyCastle.Utilities.Collections;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpEncryptedDataList : PgpObject
|
||||
{
|
||||
private IList list = Platform.CreateArrayList();
|
||||
|
||||
private InputStreamPacket data;
|
||||
|
||||
public PgpEncryptedData this[int index] => (PgpEncryptedData)list[index];
|
||||
|
||||
[Obsolete("Use 'Count' property instead")]
|
||||
public int Size => list.Count;
|
||||
|
||||
public int Count => list.Count;
|
||||
|
||||
public bool IsEmpty => list.Count == 0;
|
||||
|
||||
public PgpEncryptedDataList(BcpgInputStream bcpgInput)
|
||||
{
|
||||
while (bcpgInput.NextPacketTag() == PacketTag.PublicKeyEncryptedSession || bcpgInput.NextPacketTag() == PacketTag.SymmetricKeyEncryptedSessionKey)
|
||||
{
|
||||
list.Add(bcpgInput.ReadPacket());
|
||||
}
|
||||
data = (InputStreamPacket)bcpgInput.ReadPacket();
|
||||
for (int i = 0; i != list.Count; i++)
|
||||
{
|
||||
if (list[i] is SymmetricKeyEncSessionPacket)
|
||||
{
|
||||
list[i] = new PgpPbeEncryptedData((SymmetricKeyEncSessionPacket)list[i], data);
|
||||
}
|
||||
else
|
||||
{
|
||||
list[i] = new PgpPublicKeyEncryptedData((PublicKeyEncSessionPacket)list[i], data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("Use 'object[index]' syntax instead")]
|
||||
public object Get(int index)
|
||||
{
|
||||
return this[index];
|
||||
}
|
||||
|
||||
public IEnumerable GetEncryptedDataObjects()
|
||||
{
|
||||
return new EnumerableProxy(list);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
[Serializable]
|
||||
public class PgpException : Exception
|
||||
{
|
||||
[Obsolete("Use InnerException property")]
|
||||
public Exception UnderlyingException => base.InnerException;
|
||||
|
||||
public PgpException()
|
||||
{
|
||||
}
|
||||
|
||||
public PgpException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public PgpException(string message, Exception exception)
|
||||
: base(message, exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpExperimental : PgpObject
|
||||
{
|
||||
private readonly ExperimentalPacket p;
|
||||
|
||||
public PgpExperimental(BcpgInputStream bcpgIn)
|
||||
{
|
||||
p = (ExperimentalPacket)bcpgIn.ReadPacket();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public abstract class PgpKeyFlags
|
||||
{
|
||||
public const int CanCertify = 1;
|
||||
|
||||
public const int CanSign = 2;
|
||||
|
||||
public const int CanEncryptCommunications = 4;
|
||||
|
||||
public const int CanEncryptStorage = 8;
|
||||
|
||||
public const int MaybeSplit = 16;
|
||||
|
||||
public const int MaybeShared = 128;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpKeyPair
|
||||
{
|
||||
private readonly PgpPublicKey pub;
|
||||
|
||||
private readonly PgpPrivateKey priv;
|
||||
|
||||
public long KeyId => pub.KeyId;
|
||||
|
||||
public PgpPublicKey PublicKey => pub;
|
||||
|
||||
public PgpPrivateKey PrivateKey => priv;
|
||||
|
||||
public PgpKeyPair(PublicKeyAlgorithmTag algorithm, AsymmetricCipherKeyPair keyPair, DateTime time)
|
||||
: this(algorithm, keyPair.Public, keyPair.Private, time)
|
||||
{
|
||||
}
|
||||
|
||||
public PgpKeyPair(PublicKeyAlgorithmTag algorithm, AsymmetricKeyParameter pubKey, AsymmetricKeyParameter privKey, DateTime time)
|
||||
{
|
||||
pub = new PgpPublicKey(algorithm, pubKey, time);
|
||||
priv = new PgpPrivateKey(pub.KeyId, pub.PublicKeyPacket, privKey);
|
||||
}
|
||||
|
||||
public PgpKeyPair(PgpPublicKey pub, PgpPrivateKey priv)
|
||||
{
|
||||
this.pub = pub;
|
||||
this.priv = priv;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public abstract class PgpKeyRing : PgpObject
|
||||
{
|
||||
internal PgpKeyRing()
|
||||
{
|
||||
}
|
||||
|
||||
internal static TrustPacket ReadOptionalTrustPacket(BcpgInputStream bcpgInput)
|
||||
{
|
||||
if (bcpgInput.NextPacketTag() != PacketTag.Trust)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return (TrustPacket)bcpgInput.ReadPacket();
|
||||
}
|
||||
|
||||
internal static IList ReadSignaturesAndTrust(BcpgInputStream bcpgInput)
|
||||
{
|
||||
try
|
||||
{
|
||||
IList list = Platform.CreateArrayList();
|
||||
while (bcpgInput.NextPacketTag() == PacketTag.Signature)
|
||||
{
|
||||
SignaturePacket sigPacket = (SignaturePacket)bcpgInput.ReadPacket();
|
||||
TrustPacket trustPacket = ReadOptionalTrustPacket(bcpgInput);
|
||||
list.Add(new PgpSignature(sigPacket, trustPacket));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
catch (PgpException ex)
|
||||
{
|
||||
throw new IOException("can't create signature object: " + ex.Message, ex);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void ReadUserIDs(BcpgInputStream bcpgInput, out IList ids, out IList idTrusts, out IList idSigs)
|
||||
{
|
||||
ids = Platform.CreateArrayList();
|
||||
idTrusts = Platform.CreateArrayList();
|
||||
idSigs = Platform.CreateArrayList();
|
||||
while (bcpgInput.NextPacketTag() == PacketTag.UserId || bcpgInput.NextPacketTag() == PacketTag.UserAttribute)
|
||||
{
|
||||
Packet packet = bcpgInput.ReadPacket();
|
||||
if (packet is UserIdPacket)
|
||||
{
|
||||
UserIdPacket userIdPacket = (UserIdPacket)packet;
|
||||
ids.Add(userIdPacket.GetId());
|
||||
}
|
||||
else
|
||||
{
|
||||
UserAttributePacket userAttributePacket = (UserAttributePacket)packet;
|
||||
ids.Add(new PgpUserAttributeSubpacketVector(userAttributePacket.GetSubpackets()));
|
||||
}
|
||||
idTrusts.Add(ReadOptionalTrustPacket(bcpgInput));
|
||||
idSigs.Add(ReadSignaturesAndTrust(bcpgInput));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpKeyRingGenerator
|
||||
{
|
||||
private IList keys = Platform.CreateArrayList();
|
||||
|
||||
private string id;
|
||||
|
||||
private SymmetricKeyAlgorithmTag encAlgorithm;
|
||||
|
||||
private HashAlgorithmTag hashAlgorithm;
|
||||
|
||||
private int certificationLevel;
|
||||
|
||||
private byte[] rawPassPhrase;
|
||||
|
||||
private bool useSha1;
|
||||
|
||||
private PgpKeyPair masterKey;
|
||||
|
||||
private PgpSignatureSubpacketVector hashedPacketVector;
|
||||
|
||||
private PgpSignatureSubpacketVector unhashedPacketVector;
|
||||
|
||||
private SecureRandom rand;
|
||||
|
||||
[Obsolete("Use version taking an explicit 'useSha1' parameter instead")]
|
||||
public PgpKeyRingGenerator(int certificationLevel, PgpKeyPair masterKey, string id, SymmetricKeyAlgorithmTag encAlgorithm, char[] passPhrase, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, SecureRandom rand)
|
||||
: this(certificationLevel, masterKey, id, encAlgorithm, passPhrase, useSha1: false, hashedPackets, unhashedPackets, rand)
|
||||
{
|
||||
}
|
||||
|
||||
public PgpKeyRingGenerator(int certificationLevel, PgpKeyPair masterKey, string id, SymmetricKeyAlgorithmTag encAlgorithm, char[] passPhrase, bool useSha1, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, SecureRandom rand)
|
||||
: this(certificationLevel, masterKey, id, encAlgorithm, utf8PassPhrase: false, passPhrase, useSha1, hashedPackets, unhashedPackets, rand)
|
||||
{
|
||||
}
|
||||
|
||||
public PgpKeyRingGenerator(int certificationLevel, PgpKeyPair masterKey, string id, SymmetricKeyAlgorithmTag encAlgorithm, bool utf8PassPhrase, char[] passPhrase, bool useSha1, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, SecureRandom rand)
|
||||
: this(certificationLevel, masterKey, id, encAlgorithm, PgpUtilities.EncodePassPhrase(passPhrase, utf8PassPhrase), useSha1, hashedPackets, unhashedPackets, rand)
|
||||
{
|
||||
}
|
||||
|
||||
public PgpKeyRingGenerator(int certificationLevel, PgpKeyPair masterKey, string id, SymmetricKeyAlgorithmTag encAlgorithm, byte[] rawPassPhrase, bool useSha1, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, SecureRandom rand)
|
||||
{
|
||||
this.certificationLevel = certificationLevel;
|
||||
this.masterKey = masterKey;
|
||||
this.id = id;
|
||||
this.encAlgorithm = encAlgorithm;
|
||||
this.rawPassPhrase = rawPassPhrase;
|
||||
this.useSha1 = useSha1;
|
||||
hashedPacketVector = hashedPackets;
|
||||
unhashedPacketVector = unhashedPackets;
|
||||
this.rand = rand;
|
||||
keys.Add(new PgpSecretKey(certificationLevel, masterKey, id, encAlgorithm, rawPassPhrase, clearPassPhrase: false, useSha1, hashedPackets, unhashedPackets, rand));
|
||||
}
|
||||
|
||||
public PgpKeyRingGenerator(int certificationLevel, PgpKeyPair masterKey, string id, SymmetricKeyAlgorithmTag encAlgorithm, HashAlgorithmTag hashAlgorithm, char[] passPhrase, bool useSha1, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, SecureRandom rand)
|
||||
: this(certificationLevel, masterKey, id, encAlgorithm, hashAlgorithm, utf8PassPhrase: false, passPhrase, useSha1, hashedPackets, unhashedPackets, rand)
|
||||
{
|
||||
}
|
||||
|
||||
public PgpKeyRingGenerator(int certificationLevel, PgpKeyPair masterKey, string id, SymmetricKeyAlgorithmTag encAlgorithm, HashAlgorithmTag hashAlgorithm, bool utf8PassPhrase, char[] passPhrase, bool useSha1, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, SecureRandom rand)
|
||||
: this(certificationLevel, masterKey, id, encAlgorithm, hashAlgorithm, PgpUtilities.EncodePassPhrase(passPhrase, utf8PassPhrase), useSha1, hashedPackets, unhashedPackets, rand)
|
||||
{
|
||||
}
|
||||
|
||||
public PgpKeyRingGenerator(int certificationLevel, PgpKeyPair masterKey, string id, SymmetricKeyAlgorithmTag encAlgorithm, HashAlgorithmTag hashAlgorithm, byte[] rawPassPhrase, bool useSha1, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, SecureRandom rand)
|
||||
{
|
||||
this.certificationLevel = certificationLevel;
|
||||
this.masterKey = masterKey;
|
||||
this.id = id;
|
||||
this.encAlgorithm = encAlgorithm;
|
||||
this.rawPassPhrase = rawPassPhrase;
|
||||
this.useSha1 = useSha1;
|
||||
hashedPacketVector = hashedPackets;
|
||||
unhashedPacketVector = unhashedPackets;
|
||||
this.rand = rand;
|
||||
this.hashAlgorithm = hashAlgorithm;
|
||||
keys.Add(new PgpSecretKey(certificationLevel, masterKey, id, encAlgorithm, hashAlgorithm, rawPassPhrase, clearPassPhrase: false, useSha1, hashedPackets, unhashedPackets, rand));
|
||||
}
|
||||
|
||||
public void AddSubKey(PgpKeyPair keyPair)
|
||||
{
|
||||
AddSubKey(keyPair, hashedPacketVector, unhashedPacketVector);
|
||||
}
|
||||
|
||||
public void AddSubKey(PgpKeyPair keyPair, HashAlgorithmTag hashAlgorithm)
|
||||
{
|
||||
AddSubKey(keyPair, hashedPacketVector, unhashedPacketVector, hashAlgorithm);
|
||||
}
|
||||
|
||||
public void AddSubKey(PgpKeyPair keyPair, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets)
|
||||
{
|
||||
try
|
||||
{
|
||||
PgpSignatureGenerator pgpSignatureGenerator = new PgpSignatureGenerator(masterKey.PublicKey.Algorithm, HashAlgorithmTag.Sha1);
|
||||
pgpSignatureGenerator.InitSign(24, masterKey.PrivateKey);
|
||||
pgpSignatureGenerator.SetHashedSubpackets(hashedPackets);
|
||||
pgpSignatureGenerator.SetUnhashedSubpackets(unhashedPackets);
|
||||
IList list = Platform.CreateArrayList();
|
||||
list.Add(pgpSignatureGenerator.GenerateCertification(masterKey.PublicKey, keyPair.PublicKey));
|
||||
keys.Add(new PgpSecretKey(keyPair.PrivateKey, new PgpPublicKey(keyPair.PublicKey, null, list), encAlgorithm, rawPassPhrase, clearPassPhrase: false, useSha1, rand, isMasterKey: false));
|
||||
}
|
||||
catch (PgpException ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw new PgpException("exception adding subkey: ", exception);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddSubKey(PgpKeyPair keyPair, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, HashAlgorithmTag hashAlgorithm)
|
||||
{
|
||||
try
|
||||
{
|
||||
PgpSignatureGenerator pgpSignatureGenerator = new PgpSignatureGenerator(masterKey.PublicKey.Algorithm, hashAlgorithm);
|
||||
pgpSignatureGenerator.InitSign(24, masterKey.PrivateKey);
|
||||
pgpSignatureGenerator.SetHashedSubpackets(hashedPackets);
|
||||
pgpSignatureGenerator.SetUnhashedSubpackets(unhashedPackets);
|
||||
IList list = Platform.CreateArrayList();
|
||||
list.Add(pgpSignatureGenerator.GenerateCertification(masterKey.PublicKey, keyPair.PublicKey));
|
||||
keys.Add(new PgpSecretKey(keyPair.PrivateKey, new PgpPublicKey(keyPair.PublicKey, null, list), encAlgorithm, rawPassPhrase, clearPassPhrase: false, useSha1, rand, isMasterKey: false));
|
||||
}
|
||||
catch (PgpException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw new PgpException("exception adding subkey: ", exception);
|
||||
}
|
||||
}
|
||||
|
||||
public PgpSecretKeyRing GenerateSecretKeyRing()
|
||||
{
|
||||
return new PgpSecretKeyRing(keys);
|
||||
}
|
||||
|
||||
public PgpPublicKeyRing GeneratePublicKeyRing()
|
||||
{
|
||||
IList list = Platform.CreateArrayList();
|
||||
IEnumerator enumerator = keys.GetEnumerator();
|
||||
enumerator.MoveNext();
|
||||
PgpSecretKey pgpSecretKey = (PgpSecretKey)enumerator.Current;
|
||||
list.Add(pgpSecretKey.PublicKey);
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
pgpSecretKey = (PgpSecretKey)enumerator.Current;
|
||||
PgpPublicKey pgpPublicKey = new PgpPublicKey(pgpSecretKey.PublicKey);
|
||||
pgpPublicKey.publicPk = new PublicSubkeyPacket(pgpPublicKey.Algorithm, pgpPublicKey.CreationTime, pgpPublicKey.publicPk.Key);
|
||||
list.Add(pgpPublicKey);
|
||||
}
|
||||
return new PgpPublicKeyRing(list);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
[Serializable]
|
||||
public class PgpKeyValidationException : PgpException
|
||||
{
|
||||
public PgpKeyValidationException()
|
||||
{
|
||||
}
|
||||
|
||||
public PgpKeyValidationException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public PgpKeyValidationException(string message, Exception exception)
|
||||
: base(message, exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Utilities.Date;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpLiteralData : PgpObject
|
||||
{
|
||||
public const char Binary = 'b';
|
||||
|
||||
public const char Text = 't';
|
||||
|
||||
public const char Utf8 = 'u';
|
||||
|
||||
public const string Console = "_CONSOLE";
|
||||
|
||||
private LiteralDataPacket data;
|
||||
|
||||
public int Format => data.Format;
|
||||
|
||||
public string FileName => data.FileName;
|
||||
|
||||
public DateTime ModificationTime => DateTimeUtilities.UnixMsToDateTime(data.ModificationTime);
|
||||
|
||||
public PgpLiteralData(BcpgInputStream bcpgInput)
|
||||
{
|
||||
data = (LiteralDataPacket)bcpgInput.ReadPacket();
|
||||
}
|
||||
|
||||
public byte[] GetRawFileName()
|
||||
{
|
||||
return data.GetRawFileName();
|
||||
}
|
||||
|
||||
public Stream GetInputStream()
|
||||
{
|
||||
return data.GetInputStream();
|
||||
}
|
||||
|
||||
public Stream GetDataStream()
|
||||
{
|
||||
return GetInputStream();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
using Org.BouncyCastle.Utilities.Date;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpLiteralDataGenerator : IStreamGenerator
|
||||
{
|
||||
public const char Binary = 'b';
|
||||
|
||||
public const char Text = 't';
|
||||
|
||||
public const char Utf8 = 'u';
|
||||
|
||||
public const string Console = "_CONSOLE";
|
||||
|
||||
private BcpgOutputStream pkOut;
|
||||
|
||||
private bool oldFormat;
|
||||
|
||||
public PgpLiteralDataGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
public PgpLiteralDataGenerator(bool oldFormat)
|
||||
{
|
||||
this.oldFormat = oldFormat;
|
||||
}
|
||||
|
||||
private void WriteHeader(BcpgOutputStream outStr, char format, byte[] encName, long modificationTime)
|
||||
{
|
||||
outStr.Write((byte)format, (byte)encName.Length);
|
||||
outStr.Write(encName);
|
||||
long num = modificationTime / 1000;
|
||||
outStr.Write((byte)(num >> 24), (byte)(num >> 16), (byte)(num >> 8), (byte)num);
|
||||
}
|
||||
|
||||
public Stream Open(Stream outStr, char format, string name, long length, DateTime modificationTime)
|
||||
{
|
||||
if (pkOut != null)
|
||||
{
|
||||
throw new InvalidOperationException("generator already in open state");
|
||||
}
|
||||
if (outStr == null)
|
||||
{
|
||||
throw new ArgumentNullException("outStr");
|
||||
}
|
||||
long modificationTime2 = DateTimeUtilities.DateTimeToUnixMs(modificationTime);
|
||||
byte[] array = Strings.ToUtf8ByteArray(name);
|
||||
pkOut = new BcpgOutputStream(outStr, PacketTag.LiteralData, length + 2 + array.Length + 4, oldFormat);
|
||||
WriteHeader(pkOut, format, array, modificationTime2);
|
||||
return new WrappedGeneratorStream(this, pkOut);
|
||||
}
|
||||
|
||||
public Stream Open(Stream outStr, char format, string name, DateTime modificationTime, byte[] buffer)
|
||||
{
|
||||
if (pkOut != null)
|
||||
{
|
||||
throw new InvalidOperationException("generator already in open state");
|
||||
}
|
||||
if (outStr == null)
|
||||
{
|
||||
throw new ArgumentNullException("outStr");
|
||||
}
|
||||
long modificationTime2 = DateTimeUtilities.DateTimeToUnixMs(modificationTime);
|
||||
byte[] encName = Strings.ToUtf8ByteArray(name);
|
||||
pkOut = new BcpgOutputStream(outStr, PacketTag.LiteralData, buffer);
|
||||
WriteHeader(pkOut, format, encName, modificationTime2);
|
||||
return new WrappedGeneratorStream(this, pkOut);
|
||||
}
|
||||
|
||||
public Stream Open(Stream outStr, char format, FileInfo file)
|
||||
{
|
||||
return Open(outStr, format, file.Name, file.Length, file.LastWriteTime);
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
if (pkOut != null)
|
||||
{
|
||||
pkOut.Finish();
|
||||
pkOut.Flush();
|
||||
pkOut = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpMarker : PgpObject
|
||||
{
|
||||
private readonly MarkerPacket p;
|
||||
|
||||
public PgpMarker(BcpgInputStream bcpgIn)
|
||||
{
|
||||
p = (MarkerPacket)bcpgIn.ReadPacket();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public abstract class PgpObject
|
||||
{
|
||||
internal PgpObject()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpObjectFactory
|
||||
{
|
||||
private readonly BcpgInputStream bcpgIn;
|
||||
|
||||
public PgpObjectFactory(Stream inputStream)
|
||||
{
|
||||
bcpgIn = BcpgInputStream.Wrap(inputStream);
|
||||
}
|
||||
|
||||
public PgpObjectFactory(byte[] bytes)
|
||||
: this(new MemoryStream(bytes, writable: false))
|
||||
{
|
||||
}
|
||||
|
||||
public PgpObject NextPgpObject()
|
||||
{
|
||||
PacketTag packetTag = bcpgIn.NextPacketTag();
|
||||
if (packetTag == (PacketTag)(-1))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
switch (packetTag)
|
||||
{
|
||||
case PacketTag.Signature:
|
||||
{
|
||||
IList list2 = Platform.CreateArrayList();
|
||||
while (bcpgIn.NextPacketTag() == PacketTag.Signature)
|
||||
{
|
||||
try
|
||||
{
|
||||
list2.Add(new PgpSignature(bcpgIn));
|
||||
}
|
||||
catch (PgpException ex3)
|
||||
{
|
||||
throw new IOException("can't create signature object: " + ex3);
|
||||
}
|
||||
}
|
||||
PgpSignature[] array2 = new PgpSignature[list2.Count];
|
||||
for (int j = 0; j < list2.Count; j++)
|
||||
{
|
||||
array2[j] = (PgpSignature)list2[j];
|
||||
}
|
||||
return new PgpSignatureList(array2);
|
||||
}
|
||||
case PacketTag.SecretKey:
|
||||
try
|
||||
{
|
||||
return new PgpSecretKeyRing(bcpgIn);
|
||||
}
|
||||
catch (PgpException ex2)
|
||||
{
|
||||
throw new IOException("can't create secret key object: " + ex2);
|
||||
}
|
||||
case PacketTag.PublicKey:
|
||||
return new PgpPublicKeyRing(bcpgIn);
|
||||
case PacketTag.CompressedData:
|
||||
return new PgpCompressedData(bcpgIn);
|
||||
case PacketTag.LiteralData:
|
||||
return new PgpLiteralData(bcpgIn);
|
||||
case PacketTag.PublicKeyEncryptedSession:
|
||||
case PacketTag.SymmetricKeyEncryptedSessionKey:
|
||||
return new PgpEncryptedDataList(bcpgIn);
|
||||
case PacketTag.OnePassSignature:
|
||||
{
|
||||
IList list = Platform.CreateArrayList();
|
||||
while (bcpgIn.NextPacketTag() == PacketTag.OnePassSignature)
|
||||
{
|
||||
try
|
||||
{
|
||||
list.Add(new PgpOnePassSignature(bcpgIn));
|
||||
}
|
||||
catch (PgpException ex)
|
||||
{
|
||||
throw new IOException("can't create one pass signature object: " + ex);
|
||||
}
|
||||
}
|
||||
PgpOnePassSignature[] array = new PgpOnePassSignature[list.Count];
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
array[i] = (PgpOnePassSignature)list[i];
|
||||
}
|
||||
return new PgpOnePassSignatureList(array);
|
||||
}
|
||||
case PacketTag.Marker:
|
||||
return new PgpMarker(bcpgIn);
|
||||
case PacketTag.Experimental1:
|
||||
case PacketTag.Experimental2:
|
||||
case PacketTag.Experimental3:
|
||||
case PacketTag.Experimental4:
|
||||
return new PgpExperimental(bcpgIn);
|
||||
default:
|
||||
throw new IOException("unknown object in stream " + bcpgIn.NextPacketTag());
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("Use NextPgpObject() instead")]
|
||||
public object NextObject()
|
||||
{
|
||||
return NextPgpObject();
|
||||
}
|
||||
|
||||
public IList AllPgpObjects()
|
||||
{
|
||||
IList list = Platform.CreateArrayList();
|
||||
PgpObject value;
|
||||
while ((value = NextPgpObject()) != null)
|
||||
{
|
||||
list.Add(value);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Security;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpOnePassSignature
|
||||
{
|
||||
private OnePassSignaturePacket sigPack;
|
||||
|
||||
private int signatureType;
|
||||
|
||||
private ISigner sig;
|
||||
|
||||
private byte lastb;
|
||||
|
||||
public long KeyId => sigPack.KeyId;
|
||||
|
||||
public int SignatureType => sigPack.SignatureType;
|
||||
|
||||
public HashAlgorithmTag HashAlgorithm => sigPack.HashAlgorithm;
|
||||
|
||||
public PublicKeyAlgorithmTag KeyAlgorithm => sigPack.KeyAlgorithm;
|
||||
|
||||
internal PgpOnePassSignature(BcpgInputStream bcpgInput)
|
||||
: this((OnePassSignaturePacket)bcpgInput.ReadPacket())
|
||||
{
|
||||
}
|
||||
|
||||
internal PgpOnePassSignature(OnePassSignaturePacket sigPack)
|
||||
{
|
||||
this.sigPack = sigPack;
|
||||
signatureType = sigPack.SignatureType;
|
||||
}
|
||||
|
||||
public void InitVerify(PgpPublicKey pubKey)
|
||||
{
|
||||
lastb = 0;
|
||||
try
|
||||
{
|
||||
sig = SignerUtilities.GetSigner(PgpUtilities.GetSignatureName(sigPack.KeyAlgorithm, sigPack.HashAlgorithm));
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw new PgpException("can't set up signature object.", exception);
|
||||
}
|
||||
try
|
||||
{
|
||||
sig.Init(forSigning: false, pubKey.GetKey());
|
||||
}
|
||||
catch (InvalidKeyException exception2)
|
||||
{
|
||||
throw new PgpException("invalid key.", exception2);
|
||||
}
|
||||
}
|
||||
|
||||
public void Update(byte b)
|
||||
{
|
||||
if (signatureType == 1)
|
||||
{
|
||||
doCanonicalUpdateByte(b);
|
||||
}
|
||||
else
|
||||
{
|
||||
sig.Update(b);
|
||||
}
|
||||
}
|
||||
|
||||
private void doCanonicalUpdateByte(byte b)
|
||||
{
|
||||
switch (b)
|
||||
{
|
||||
case 13:
|
||||
doUpdateCRLF();
|
||||
break;
|
||||
case 10:
|
||||
if (lastb != 13)
|
||||
{
|
||||
doUpdateCRLF();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
sig.Update(b);
|
||||
break;
|
||||
}
|
||||
lastb = b;
|
||||
}
|
||||
|
||||
private void doUpdateCRLF()
|
||||
{
|
||||
sig.Update(13);
|
||||
sig.Update(10);
|
||||
}
|
||||
|
||||
public void Update(byte[] bytes)
|
||||
{
|
||||
if (signatureType == 1)
|
||||
{
|
||||
for (int i = 0; i != bytes.Length; i++)
|
||||
{
|
||||
doCanonicalUpdateByte(bytes[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sig.BlockUpdate(bytes, 0, bytes.Length);
|
||||
}
|
||||
}
|
||||
|
||||
public void Update(byte[] bytes, int off, int length)
|
||||
{
|
||||
if (signatureType == 1)
|
||||
{
|
||||
int num = off + length;
|
||||
for (int i = off; i != num; i++)
|
||||
{
|
||||
doCanonicalUpdateByte(bytes[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sig.BlockUpdate(bytes, off, length);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Verify(PgpSignature pgpSig)
|
||||
{
|
||||
byte[] signatureTrailer = pgpSig.GetSignatureTrailer();
|
||||
sig.BlockUpdate(signatureTrailer, 0, signatureTrailer.Length);
|
||||
return sig.VerifySignature(pgpSig.GetSignature());
|
||||
}
|
||||
|
||||
public byte[] GetEncoded()
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
Encode(memoryStream);
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
|
||||
public void Encode(Stream outStr)
|
||||
{
|
||||
BcpgOutputStream.Wrap(outStr).WritePacket(sigPack);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpOnePassSignatureList : PgpObject
|
||||
{
|
||||
private readonly PgpOnePassSignature[] sigs;
|
||||
|
||||
public PgpOnePassSignature this[int index] => sigs[index];
|
||||
|
||||
[Obsolete("Use 'Count' property instead")]
|
||||
public int Size => sigs.Length;
|
||||
|
||||
public int Count => sigs.Length;
|
||||
|
||||
public bool IsEmpty => sigs.Length == 0;
|
||||
|
||||
public PgpOnePassSignatureList(PgpOnePassSignature[] sigs)
|
||||
{
|
||||
this.sigs = (PgpOnePassSignature[])sigs.Clone();
|
||||
}
|
||||
|
||||
public PgpOnePassSignatureList(PgpOnePassSignature sig)
|
||||
{
|
||||
sigs = new PgpOnePassSignature[1] { sig };
|
||||
}
|
||||
|
||||
[Obsolete("Use 'object[index]' syntax instead")]
|
||||
public PgpOnePassSignature Get(int index)
|
||||
{
|
||||
return this[index];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public sealed class PgpPad
|
||||
{
|
||||
private PgpPad()
|
||||
{
|
||||
}
|
||||
|
||||
public static byte[] PadSessionData(byte[] sessionInfo)
|
||||
{
|
||||
byte[] array = new byte[40];
|
||||
Array.Copy(sessionInfo, 0, array, 0, sessionInfo.Length);
|
||||
byte b = (byte)(array.Length - sessionInfo.Length);
|
||||
for (int i = sessionInfo.Length; i != array.Length; i++)
|
||||
{
|
||||
array[i] = b;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
public static byte[] UnpadSessionData(byte[] encoded)
|
||||
{
|
||||
byte b = encoded[^1];
|
||||
for (int i = encoded.Length - b; i != encoded.Length; i++)
|
||||
{
|
||||
if (encoded[i] != b)
|
||||
{
|
||||
throw new PgpException("bad padding found in session data");
|
||||
}
|
||||
}
|
||||
byte[] array = new byte[encoded.Length - b];
|
||||
Array.Copy(encoded, 0, array, 0, array.Length);
|
||||
return array;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.IO;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Utilities.IO;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpPbeEncryptedData : PgpEncryptedData
|
||||
{
|
||||
private readonly SymmetricKeyEncSessionPacket keyData;
|
||||
|
||||
internal PgpPbeEncryptedData(SymmetricKeyEncSessionPacket keyData, InputStreamPacket encData)
|
||||
: base(encData)
|
||||
{
|
||||
this.keyData = keyData;
|
||||
}
|
||||
|
||||
public override Stream GetInputStream()
|
||||
{
|
||||
return encData.GetInputStream();
|
||||
}
|
||||
|
||||
public Stream GetDataStream(char[] passPhrase)
|
||||
{
|
||||
return DoGetDataStream(PgpUtilities.EncodePassPhrase(passPhrase, utf8: false), clearPassPhrase: true);
|
||||
}
|
||||
|
||||
public Stream GetDataStreamUtf8(char[] passPhrase)
|
||||
{
|
||||
return DoGetDataStream(PgpUtilities.EncodePassPhrase(passPhrase, utf8: true), clearPassPhrase: true);
|
||||
}
|
||||
|
||||
public Stream GetDataStreamRaw(byte[] rawPassPhrase)
|
||||
{
|
||||
return DoGetDataStream(rawPassPhrase, clearPassPhrase: false);
|
||||
}
|
||||
|
||||
internal Stream DoGetDataStream(byte[] rawPassPhrase, bool clearPassPhrase)
|
||||
{
|
||||
try
|
||||
{
|
||||
SymmetricKeyAlgorithmTag symmetricKeyAlgorithmTag = keyData.EncAlgorithm;
|
||||
KeyParameter parameters = PgpUtilities.DoMakeKeyFromPassPhrase(symmetricKeyAlgorithmTag, keyData.S2k, rawPassPhrase, clearPassPhrase);
|
||||
byte[] secKeyData = keyData.GetSecKeyData();
|
||||
if (secKeyData != null && secKeyData.Length > 0)
|
||||
{
|
||||
IBufferedCipher cipher = CipherUtilities.GetCipher(PgpUtilities.GetSymmetricCipherName(symmetricKeyAlgorithmTag) + "/CFB/NoPadding");
|
||||
cipher.Init(forEncryption: false, new ParametersWithIV(parameters, new byte[cipher.GetBlockSize()]));
|
||||
byte[] array = cipher.DoFinal(secKeyData);
|
||||
symmetricKeyAlgorithmTag = (SymmetricKeyAlgorithmTag)array[0];
|
||||
parameters = ParameterUtilities.CreateKeyParameter(PgpUtilities.GetSymmetricCipherName(symmetricKeyAlgorithmTag), array, 1, array.Length - 1);
|
||||
}
|
||||
IBufferedCipher bufferedCipher = CreateStreamCipher(symmetricKeyAlgorithmTag);
|
||||
byte[] array2 = new byte[bufferedCipher.GetBlockSize()];
|
||||
bufferedCipher.Init(forEncryption: false, new ParametersWithIV(parameters, array2));
|
||||
encStream = BcpgInputStream.Wrap(new CipherStream(encData.GetInputStream(), bufferedCipher, null));
|
||||
if (encData is SymmetricEncIntegrityPacket)
|
||||
{
|
||||
truncStream = new TruncatedStream(encStream);
|
||||
string digestName = PgpUtilities.GetDigestName(HashAlgorithmTag.Sha1);
|
||||
IDigest digest = DigestUtilities.GetDigest(digestName);
|
||||
encStream = new DigestStream(truncStream, digest, null);
|
||||
}
|
||||
if (Streams.ReadFully(encStream, array2, 0, array2.Length) < array2.Length)
|
||||
{
|
||||
throw new EndOfStreamException("unexpected end of stream.");
|
||||
}
|
||||
int num = encStream.ReadByte();
|
||||
int num2 = encStream.ReadByte();
|
||||
if (num < 0 || num2 < 0)
|
||||
{
|
||||
throw new EndOfStreamException("unexpected end of stream.");
|
||||
}
|
||||
bool flag = array2[^2] == (byte)num && array2[^1] == (byte)num2;
|
||||
bool flag2 = num == 0 && num2 == 0;
|
||||
if (!flag && !flag2)
|
||||
{
|
||||
throw new PgpDataValidationException("quick check failed.");
|
||||
}
|
||||
return encStream;
|
||||
}
|
||||
catch (PgpException ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw new PgpException("Exception creating cipher", exception);
|
||||
}
|
||||
}
|
||||
|
||||
private IBufferedCipher CreateStreamCipher(SymmetricKeyAlgorithmTag keyAlgorithm)
|
||||
{
|
||||
string text = ((encData is SymmetricEncIntegrityPacket) ? "CFB" : "OpenPGPCFB");
|
||||
string algorithm = PgpUtilities.GetSymmetricCipherName(keyAlgorithm) + "/" + text + "/NoPadding";
|
||||
return CipherUtilities.GetCipher(algorithm);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpPrivateKey
|
||||
{
|
||||
private readonly long keyID;
|
||||
|
||||
private readonly PublicKeyPacket publicKeyPacket;
|
||||
|
||||
private readonly AsymmetricKeyParameter privateKey;
|
||||
|
||||
public long KeyId => keyID;
|
||||
|
||||
public PublicKeyPacket PublicKeyPacket => publicKeyPacket;
|
||||
|
||||
public AsymmetricKeyParameter Key => privateKey;
|
||||
|
||||
public PgpPrivateKey(long keyID, PublicKeyPacket publicKeyPacket, AsymmetricKeyParameter privateKey)
|
||||
{
|
||||
if (!privateKey.IsPrivate)
|
||||
{
|
||||
throw new ArgumentException("Expected a private key", "privateKey");
|
||||
}
|
||||
this.keyID = keyID;
|
||||
this.publicKeyPacket = publicKeyPacket;
|
||||
this.privateKey = privateKey;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,738 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Asn1.X9;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Generators;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Math;
|
||||
using Org.BouncyCastle.Math.EC;
|
||||
using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
using Org.BouncyCastle.Utilities.Collections;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpPublicKey
|
||||
{
|
||||
private static readonly int[] MasterKeyCertificationTypes = new int[4] { 19, 18, 17, 16 };
|
||||
|
||||
private long keyId;
|
||||
|
||||
private byte[] fingerprint;
|
||||
|
||||
private int keyStrength;
|
||||
|
||||
internal PublicKeyPacket publicPk;
|
||||
|
||||
internal TrustPacket trustPk;
|
||||
|
||||
internal IList keySigs = Platform.CreateArrayList();
|
||||
|
||||
internal IList ids = Platform.CreateArrayList();
|
||||
|
||||
internal IList idTrusts = Platform.CreateArrayList();
|
||||
|
||||
internal IList idSigs = Platform.CreateArrayList();
|
||||
|
||||
internal IList subSigs;
|
||||
|
||||
public int Version => publicPk.Version;
|
||||
|
||||
public DateTime CreationTime => publicPk.GetTime();
|
||||
|
||||
[Obsolete("Use 'GetValidSeconds' instead")]
|
||||
public int ValidDays
|
||||
{
|
||||
get
|
||||
{
|
||||
if (publicPk.Version <= 3)
|
||||
{
|
||||
return publicPk.ValidDays;
|
||||
}
|
||||
long validSeconds = GetValidSeconds();
|
||||
if (validSeconds <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int val = (int)(validSeconds / 86400);
|
||||
return System.Math.Max(1, val);
|
||||
}
|
||||
}
|
||||
|
||||
public long KeyId => keyId;
|
||||
|
||||
public bool IsEncryptionKey
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (publicPk.Algorithm)
|
||||
{
|
||||
case PublicKeyAlgorithmTag.RsaGeneral:
|
||||
case PublicKeyAlgorithmTag.RsaEncrypt:
|
||||
case PublicKeyAlgorithmTag.ElGamalEncrypt:
|
||||
case PublicKeyAlgorithmTag.EC:
|
||||
case PublicKeyAlgorithmTag.ElGamalGeneral:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsMasterKey => subSigs == null;
|
||||
|
||||
public PublicKeyAlgorithmTag Algorithm => publicPk.Algorithm;
|
||||
|
||||
public int BitStrength => keyStrength;
|
||||
|
||||
public PublicKeyPacket PublicKeyPacket => publicPk;
|
||||
|
||||
public static byte[] CalculateFingerprint(PublicKeyPacket publicPk)
|
||||
{
|
||||
IBcpgKey key = publicPk.Key;
|
||||
IDigest digest;
|
||||
if (publicPk.Version <= 3)
|
||||
{
|
||||
RsaPublicBcpgKey rsaPublicBcpgKey = (RsaPublicBcpgKey)key;
|
||||
try
|
||||
{
|
||||
digest = DigestUtilities.GetDigest("MD5");
|
||||
UpdateDigest(digest, rsaPublicBcpgKey.Modulus);
|
||||
UpdateDigest(digest, rsaPublicBcpgKey.PublicExponent);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new PgpException("can't encode key components: " + ex.Message, ex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] encodedContents = publicPk.GetEncodedContents();
|
||||
digest = DigestUtilities.GetDigest("SHA1");
|
||||
digest.Update(153);
|
||||
digest.Update((byte)(encodedContents.Length >> 8));
|
||||
digest.Update((byte)encodedContents.Length);
|
||||
digest.BlockUpdate(encodedContents, 0, encodedContents.Length);
|
||||
}
|
||||
catch (Exception ex2)
|
||||
{
|
||||
throw new PgpException("can't encode key components: " + ex2.Message, ex2);
|
||||
}
|
||||
}
|
||||
return DigestUtilities.DoFinal(digest);
|
||||
}
|
||||
|
||||
private static void UpdateDigest(IDigest d, BigInteger b)
|
||||
{
|
||||
byte[] array = b.ToByteArrayUnsigned();
|
||||
d.BlockUpdate(array, 0, array.Length);
|
||||
}
|
||||
|
||||
private void Init()
|
||||
{
|
||||
IBcpgKey key = publicPk.Key;
|
||||
fingerprint = CalculateFingerprint(publicPk);
|
||||
if (publicPk.Version <= 3)
|
||||
{
|
||||
RsaPublicBcpgKey rsaPublicBcpgKey = (RsaPublicBcpgKey)key;
|
||||
keyId = rsaPublicBcpgKey.Modulus.LongValue;
|
||||
keyStrength = rsaPublicBcpgKey.Modulus.BitLength;
|
||||
return;
|
||||
}
|
||||
keyId = (long)(((ulong)fingerprint[fingerprint.Length - 8] << 56) | ((ulong)fingerprint[fingerprint.Length - 7] << 48) | ((ulong)fingerprint[fingerprint.Length - 6] << 40) | ((ulong)fingerprint[fingerprint.Length - 5] << 32) | ((ulong)fingerprint[fingerprint.Length - 4] << 24) | ((ulong)fingerprint[fingerprint.Length - 3] << 16) | ((ulong)fingerprint[fingerprint.Length - 2] << 8) | fingerprint[fingerprint.Length - 1]);
|
||||
if (key is RsaPublicBcpgKey)
|
||||
{
|
||||
keyStrength = ((RsaPublicBcpgKey)key).Modulus.BitLength;
|
||||
}
|
||||
else if (key is DsaPublicBcpgKey)
|
||||
{
|
||||
keyStrength = ((DsaPublicBcpgKey)key).P.BitLength;
|
||||
}
|
||||
else if (key is ElGamalPublicBcpgKey)
|
||||
{
|
||||
keyStrength = ((ElGamalPublicBcpgKey)key).P.BitLength;
|
||||
}
|
||||
else if (key is ECPublicBcpgKey)
|
||||
{
|
||||
keyStrength = ECKeyPairGenerator.FindECCurveByOid(((ECPublicBcpgKey)key).CurveOid).Curve.FieldSize;
|
||||
}
|
||||
}
|
||||
|
||||
public PgpPublicKey(PublicKeyAlgorithmTag algorithm, AsymmetricKeyParameter pubKey, DateTime time)
|
||||
{
|
||||
if (pubKey.IsPrivate)
|
||||
{
|
||||
throw new ArgumentException("Expected a public key", "pubKey");
|
||||
}
|
||||
IBcpgKey key;
|
||||
if (pubKey is RsaKeyParameters)
|
||||
{
|
||||
RsaKeyParameters rsaKeyParameters = (RsaKeyParameters)pubKey;
|
||||
key = new RsaPublicBcpgKey(rsaKeyParameters.Modulus, rsaKeyParameters.Exponent);
|
||||
}
|
||||
else if (pubKey is DsaPublicKeyParameters)
|
||||
{
|
||||
DsaPublicKeyParameters dsaPublicKeyParameters = (DsaPublicKeyParameters)pubKey;
|
||||
DsaParameters parameters = dsaPublicKeyParameters.Parameters;
|
||||
key = new DsaPublicBcpgKey(parameters.P, parameters.Q, parameters.G, dsaPublicKeyParameters.Y);
|
||||
}
|
||||
else if (pubKey is ECPublicKeyParameters)
|
||||
{
|
||||
ECPublicKeyParameters eCPublicKeyParameters = (ECPublicKeyParameters)pubKey;
|
||||
key = algorithm switch
|
||||
{
|
||||
PublicKeyAlgorithmTag.EC => new ECDHPublicBcpgKey(eCPublicKeyParameters.PublicKeyParamSet, eCPublicKeyParameters.Q, HashAlgorithmTag.Sha256, SymmetricKeyAlgorithmTag.Aes128),
|
||||
PublicKeyAlgorithmTag.ECDsa => new ECDsaPublicBcpgKey(eCPublicKeyParameters.PublicKeyParamSet, eCPublicKeyParameters.Q),
|
||||
_ => throw new PgpException("unknown EC algorithm"),
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(pubKey is ElGamalPublicKeyParameters))
|
||||
{
|
||||
throw new PgpException("unknown key class");
|
||||
}
|
||||
ElGamalPublicKeyParameters elGamalPublicKeyParameters = (ElGamalPublicKeyParameters)pubKey;
|
||||
ElGamalParameters parameters2 = elGamalPublicKeyParameters.Parameters;
|
||||
key = new ElGamalPublicBcpgKey(parameters2.P, parameters2.G, elGamalPublicKeyParameters.Y);
|
||||
}
|
||||
publicPk = new PublicKeyPacket(algorithm, time, key);
|
||||
ids = Platform.CreateArrayList();
|
||||
idSigs = Platform.CreateArrayList();
|
||||
try
|
||||
{
|
||||
Init();
|
||||
}
|
||||
catch (IOException exception)
|
||||
{
|
||||
throw new PgpException("exception calculating keyId", exception);
|
||||
}
|
||||
}
|
||||
|
||||
public PgpPublicKey(PublicKeyPacket publicPk)
|
||||
: this(publicPk, Platform.CreateArrayList(), Platform.CreateArrayList())
|
||||
{
|
||||
}
|
||||
|
||||
internal PgpPublicKey(PublicKeyPacket publicPk, TrustPacket trustPk, IList sigs)
|
||||
{
|
||||
this.publicPk = publicPk;
|
||||
this.trustPk = trustPk;
|
||||
subSigs = sigs;
|
||||
Init();
|
||||
}
|
||||
|
||||
internal PgpPublicKey(PgpPublicKey key, TrustPacket trust, IList subSigs)
|
||||
{
|
||||
publicPk = key.publicPk;
|
||||
trustPk = trust;
|
||||
this.subSigs = subSigs;
|
||||
fingerprint = key.fingerprint;
|
||||
keyId = key.keyId;
|
||||
keyStrength = key.keyStrength;
|
||||
}
|
||||
|
||||
internal PgpPublicKey(PgpPublicKey pubKey)
|
||||
{
|
||||
publicPk = pubKey.publicPk;
|
||||
keySigs = Platform.CreateArrayList(pubKey.keySigs);
|
||||
ids = Platform.CreateArrayList(pubKey.ids);
|
||||
idTrusts = Platform.CreateArrayList(pubKey.idTrusts);
|
||||
idSigs = Platform.CreateArrayList(pubKey.idSigs.Count);
|
||||
for (int i = 0; i != pubKey.idSigs.Count; i++)
|
||||
{
|
||||
idSigs.Add(Platform.CreateArrayList((IList)pubKey.idSigs[i]));
|
||||
}
|
||||
if (pubKey.subSigs != null)
|
||||
{
|
||||
subSigs = Platform.CreateArrayList(pubKey.subSigs.Count);
|
||||
for (int j = 0; j != pubKey.subSigs.Count; j++)
|
||||
{
|
||||
subSigs.Add(pubKey.subSigs[j]);
|
||||
}
|
||||
}
|
||||
fingerprint = pubKey.fingerprint;
|
||||
keyId = pubKey.keyId;
|
||||
keyStrength = pubKey.keyStrength;
|
||||
}
|
||||
|
||||
internal PgpPublicKey(PublicKeyPacket publicPk, TrustPacket trustPk, IList keySigs, IList ids, IList idTrusts, IList idSigs)
|
||||
{
|
||||
this.publicPk = publicPk;
|
||||
this.trustPk = trustPk;
|
||||
this.keySigs = keySigs;
|
||||
this.ids = ids;
|
||||
this.idTrusts = idTrusts;
|
||||
this.idSigs = idSigs;
|
||||
Init();
|
||||
}
|
||||
|
||||
internal PgpPublicKey(PublicKeyPacket publicPk, IList ids, IList idSigs)
|
||||
{
|
||||
this.publicPk = publicPk;
|
||||
this.ids = ids;
|
||||
this.idSigs = idSigs;
|
||||
Init();
|
||||
}
|
||||
|
||||
public byte[] GetTrustData()
|
||||
{
|
||||
if (trustPk == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return Arrays.Clone(trustPk.GetLevelAndTrustAmount());
|
||||
}
|
||||
|
||||
public long GetValidSeconds()
|
||||
{
|
||||
if (publicPk.Version <= 3)
|
||||
{
|
||||
return (long)publicPk.ValidDays * 86400L;
|
||||
}
|
||||
if (IsMasterKey)
|
||||
{
|
||||
for (int i = 0; i != MasterKeyCertificationTypes.Length; i++)
|
||||
{
|
||||
long expirationTimeFromSig = GetExpirationTimeFromSig(selfSigned: true, MasterKeyCertificationTypes[i]);
|
||||
if (expirationTimeFromSig >= 0)
|
||||
{
|
||||
return expirationTimeFromSig;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
long expirationTimeFromSig2 = GetExpirationTimeFromSig(selfSigned: false, 24);
|
||||
if (expirationTimeFromSig2 >= 0)
|
||||
{
|
||||
return expirationTimeFromSig2;
|
||||
}
|
||||
}
|
||||
return 0L;
|
||||
}
|
||||
|
||||
private long GetExpirationTimeFromSig(bool selfSigned, int signatureType)
|
||||
{
|
||||
long num = -1L;
|
||||
long num2 = -1L;
|
||||
foreach (PgpSignature item in GetSignaturesOfType(signatureType))
|
||||
{
|
||||
if (selfSigned && item.KeyId != KeyId)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
PgpSignatureSubpacketVector hashedSubPackets = item.GetHashedSubPackets();
|
||||
if (hashedSubPackets == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
long keyExpirationTime = hashedSubPackets.GetKeyExpirationTime();
|
||||
if (item.KeyId == KeyId)
|
||||
{
|
||||
if (item.CreationTime.Ticks > num2)
|
||||
{
|
||||
num2 = item.CreationTime.Ticks;
|
||||
num = keyExpirationTime;
|
||||
}
|
||||
}
|
||||
else if (keyExpirationTime == 0 || keyExpirationTime > num)
|
||||
{
|
||||
num = keyExpirationTime;
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
public byte[] GetFingerprint()
|
||||
{
|
||||
return (byte[])fingerprint.Clone();
|
||||
}
|
||||
|
||||
public AsymmetricKeyParameter GetKey()
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (publicPk.Algorithm)
|
||||
{
|
||||
case PublicKeyAlgorithmTag.RsaGeneral:
|
||||
case PublicKeyAlgorithmTag.RsaEncrypt:
|
||||
case PublicKeyAlgorithmTag.RsaSign:
|
||||
{
|
||||
RsaPublicBcpgKey rsaPublicBcpgKey = (RsaPublicBcpgKey)publicPk.Key;
|
||||
return new RsaKeyParameters(isPrivate: false, rsaPublicBcpgKey.Modulus, rsaPublicBcpgKey.PublicExponent);
|
||||
}
|
||||
case PublicKeyAlgorithmTag.Dsa:
|
||||
{
|
||||
DsaPublicBcpgKey dsaPublicBcpgKey = (DsaPublicBcpgKey)publicPk.Key;
|
||||
return new DsaPublicKeyParameters(dsaPublicBcpgKey.Y, new DsaParameters(dsaPublicBcpgKey.P, dsaPublicBcpgKey.Q, dsaPublicBcpgKey.G));
|
||||
}
|
||||
case PublicKeyAlgorithmTag.ECDsa:
|
||||
return GetECKey("ECDSA");
|
||||
case PublicKeyAlgorithmTag.EC:
|
||||
return GetECKey("ECDH");
|
||||
case PublicKeyAlgorithmTag.ElGamalEncrypt:
|
||||
case PublicKeyAlgorithmTag.ElGamalGeneral:
|
||||
{
|
||||
ElGamalPublicBcpgKey elGamalPublicBcpgKey = (ElGamalPublicBcpgKey)publicPk.Key;
|
||||
return new ElGamalPublicKeyParameters(elGamalPublicBcpgKey.Y, new ElGamalParameters(elGamalPublicBcpgKey.P, elGamalPublicBcpgKey.G));
|
||||
}
|
||||
default:
|
||||
throw new PgpException("unknown public key algorithm encountered");
|
||||
}
|
||||
}
|
||||
catch (PgpException ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw new PgpException("exception constructing public key", exception);
|
||||
}
|
||||
}
|
||||
|
||||
private ECPublicKeyParameters GetECKey(string algorithm)
|
||||
{
|
||||
ECPublicBcpgKey eCPublicBcpgKey = (ECPublicBcpgKey)publicPk.Key;
|
||||
X9ECParameters x9ECParameters = ECKeyPairGenerator.FindECCurveByOid(eCPublicBcpgKey.CurveOid);
|
||||
ECPoint q = x9ECParameters.Curve.DecodePoint(BigIntegers.AsUnsignedByteArray(eCPublicBcpgKey.EncodedPoint));
|
||||
return new ECPublicKeyParameters(algorithm, q, eCPublicBcpgKey.CurveOid);
|
||||
}
|
||||
|
||||
public IEnumerable GetUserIds()
|
||||
{
|
||||
IList list = Platform.CreateArrayList();
|
||||
foreach (object id in ids)
|
||||
{
|
||||
if (id is string)
|
||||
{
|
||||
list.Add(id);
|
||||
}
|
||||
}
|
||||
return new EnumerableProxy(list);
|
||||
}
|
||||
|
||||
public IEnumerable GetUserAttributes()
|
||||
{
|
||||
IList list = Platform.CreateArrayList();
|
||||
foreach (object id in ids)
|
||||
{
|
||||
if (id is PgpUserAttributeSubpacketVector)
|
||||
{
|
||||
list.Add(id);
|
||||
}
|
||||
}
|
||||
return new EnumerableProxy(list);
|
||||
}
|
||||
|
||||
public IEnumerable GetSignaturesForId(string id)
|
||||
{
|
||||
if (id == null)
|
||||
{
|
||||
throw new ArgumentNullException("id");
|
||||
}
|
||||
for (int i = 0; i != ids.Count; i++)
|
||||
{
|
||||
if (id.Equals(ids[i]))
|
||||
{
|
||||
return new EnumerableProxy((IList)idSigs[i]);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public IEnumerable GetSignaturesForUserAttribute(PgpUserAttributeSubpacketVector userAttributes)
|
||||
{
|
||||
for (int i = 0; i != ids.Count; i++)
|
||||
{
|
||||
if (userAttributes.Equals(ids[i]))
|
||||
{
|
||||
return new EnumerableProxy((IList)idSigs[i]);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public IEnumerable GetSignaturesOfType(int signatureType)
|
||||
{
|
||||
IList list = Platform.CreateArrayList();
|
||||
foreach (PgpSignature signature in GetSignatures())
|
||||
{
|
||||
if (signature.SignatureType == signatureType)
|
||||
{
|
||||
list.Add(signature);
|
||||
}
|
||||
}
|
||||
return new EnumerableProxy(list);
|
||||
}
|
||||
|
||||
public IEnumerable GetSignatures()
|
||||
{
|
||||
IList list = subSigs;
|
||||
if (list == null)
|
||||
{
|
||||
list = Platform.CreateArrayList(keySigs);
|
||||
foreach (ICollection idSig in idSigs)
|
||||
{
|
||||
CollectionUtilities.AddRange(list, idSig);
|
||||
}
|
||||
}
|
||||
return new EnumerableProxy(list);
|
||||
}
|
||||
|
||||
public IEnumerable GetKeySignatures()
|
||||
{
|
||||
IList list = subSigs;
|
||||
if (list == null)
|
||||
{
|
||||
list = Platform.CreateArrayList(keySigs);
|
||||
}
|
||||
return new EnumerableProxy(list);
|
||||
}
|
||||
|
||||
public byte[] GetEncoded()
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
Encode(memoryStream);
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
|
||||
public void Encode(Stream outStr)
|
||||
{
|
||||
BcpgOutputStream bcpgOutputStream = BcpgOutputStream.Wrap(outStr);
|
||||
bcpgOutputStream.WritePacket(publicPk);
|
||||
if (trustPk != null)
|
||||
{
|
||||
bcpgOutputStream.WritePacket(trustPk);
|
||||
}
|
||||
if (subSigs == null)
|
||||
{
|
||||
foreach (PgpSignature keySig in keySigs)
|
||||
{
|
||||
keySig.Encode(bcpgOutputStream);
|
||||
}
|
||||
for (int i = 0; i != ids.Count; i++)
|
||||
{
|
||||
if (ids[i] is string)
|
||||
{
|
||||
string id = (string)ids[i];
|
||||
bcpgOutputStream.WritePacket(new UserIdPacket(id));
|
||||
}
|
||||
else
|
||||
{
|
||||
PgpUserAttributeSubpacketVector pgpUserAttributeSubpacketVector = (PgpUserAttributeSubpacketVector)ids[i];
|
||||
bcpgOutputStream.WritePacket(new UserAttributePacket(pgpUserAttributeSubpacketVector.ToSubpacketArray()));
|
||||
}
|
||||
if (idTrusts[i] != null)
|
||||
{
|
||||
bcpgOutputStream.WritePacket((ContainedPacket)idTrusts[i]);
|
||||
}
|
||||
foreach (PgpSignature item in (IList)idSigs[i])
|
||||
{
|
||||
item.Encode(bcpgOutputStream);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
foreach (PgpSignature subSig in subSigs)
|
||||
{
|
||||
subSig.Encode(bcpgOutputStream);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsRevoked()
|
||||
{
|
||||
int num = 0;
|
||||
bool flag = false;
|
||||
if (IsMasterKey)
|
||||
{
|
||||
while (!flag && num < keySigs.Count)
|
||||
{
|
||||
if (((PgpSignature)keySigs[num++]).SignatureType == 32)
|
||||
{
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (!flag && num < subSigs.Count)
|
||||
{
|
||||
if (((PgpSignature)subSigs[num++]).SignatureType == 40)
|
||||
{
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
public static PgpPublicKey AddCertification(PgpPublicKey key, string id, PgpSignature certification)
|
||||
{
|
||||
return AddCert(key, id, certification);
|
||||
}
|
||||
|
||||
public static PgpPublicKey AddCertification(PgpPublicKey key, PgpUserAttributeSubpacketVector userAttributes, PgpSignature certification)
|
||||
{
|
||||
return AddCert(key, userAttributes, certification);
|
||||
}
|
||||
|
||||
private static PgpPublicKey AddCert(PgpPublicKey key, object id, PgpSignature certification)
|
||||
{
|
||||
PgpPublicKey pgpPublicKey = new PgpPublicKey(key);
|
||||
IList list = null;
|
||||
for (int i = 0; i != pgpPublicKey.ids.Count; i++)
|
||||
{
|
||||
if (id.Equals(pgpPublicKey.ids[i]))
|
||||
{
|
||||
list = (IList)pgpPublicKey.idSigs[i];
|
||||
}
|
||||
}
|
||||
if (list != null)
|
||||
{
|
||||
list.Add(certification);
|
||||
}
|
||||
else
|
||||
{
|
||||
list = Platform.CreateArrayList();
|
||||
list.Add(certification);
|
||||
pgpPublicKey.ids.Add(id);
|
||||
pgpPublicKey.idTrusts.Add(null);
|
||||
pgpPublicKey.idSigs.Add(list);
|
||||
}
|
||||
return pgpPublicKey;
|
||||
}
|
||||
|
||||
public static PgpPublicKey RemoveCertification(PgpPublicKey key, PgpUserAttributeSubpacketVector userAttributes)
|
||||
{
|
||||
return RemoveCert(key, userAttributes);
|
||||
}
|
||||
|
||||
public static PgpPublicKey RemoveCertification(PgpPublicKey key, string id)
|
||||
{
|
||||
return RemoveCert(key, id);
|
||||
}
|
||||
|
||||
private static PgpPublicKey RemoveCert(PgpPublicKey key, object id)
|
||||
{
|
||||
PgpPublicKey pgpPublicKey = new PgpPublicKey(key);
|
||||
bool flag = false;
|
||||
for (int i = 0; i < pgpPublicKey.ids.Count; i++)
|
||||
{
|
||||
if (id.Equals(pgpPublicKey.ids[i]))
|
||||
{
|
||||
flag = true;
|
||||
pgpPublicKey.ids.RemoveAt(i);
|
||||
pgpPublicKey.idTrusts.RemoveAt(i);
|
||||
pgpPublicKey.idSigs.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
if (!flag)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return pgpPublicKey;
|
||||
}
|
||||
|
||||
public static PgpPublicKey RemoveCertification(PgpPublicKey key, string id, PgpSignature certification)
|
||||
{
|
||||
return RemoveCert(key, id, certification);
|
||||
}
|
||||
|
||||
public static PgpPublicKey RemoveCertification(PgpPublicKey key, PgpUserAttributeSubpacketVector userAttributes, PgpSignature certification)
|
||||
{
|
||||
return RemoveCert(key, userAttributes, certification);
|
||||
}
|
||||
|
||||
private static PgpPublicKey RemoveCert(PgpPublicKey key, object id, PgpSignature certification)
|
||||
{
|
||||
PgpPublicKey pgpPublicKey = new PgpPublicKey(key);
|
||||
bool flag = false;
|
||||
for (int i = 0; i < pgpPublicKey.ids.Count; i++)
|
||||
{
|
||||
if (id.Equals(pgpPublicKey.ids[i]))
|
||||
{
|
||||
IList list = (IList)pgpPublicKey.idSigs[i];
|
||||
flag = list.Contains(certification);
|
||||
if (flag)
|
||||
{
|
||||
list.Remove(certification);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!flag)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return pgpPublicKey;
|
||||
}
|
||||
|
||||
public static PgpPublicKey AddCertification(PgpPublicKey key, PgpSignature certification)
|
||||
{
|
||||
if (key.IsMasterKey)
|
||||
{
|
||||
if (certification.SignatureType == 40)
|
||||
{
|
||||
throw new ArgumentException("signature type incorrect for master key revocation.");
|
||||
}
|
||||
}
|
||||
else if (certification.SignatureType == 32)
|
||||
{
|
||||
throw new ArgumentException("signature type incorrect for sub-key revocation.");
|
||||
}
|
||||
PgpPublicKey pgpPublicKey = new PgpPublicKey(key);
|
||||
if (pgpPublicKey.subSigs != null)
|
||||
{
|
||||
pgpPublicKey.subSigs.Add(certification);
|
||||
}
|
||||
else
|
||||
{
|
||||
pgpPublicKey.keySigs.Add(certification);
|
||||
}
|
||||
return pgpPublicKey;
|
||||
}
|
||||
|
||||
public static PgpPublicKey RemoveCertification(PgpPublicKey key, PgpSignature certification)
|
||||
{
|
||||
PgpPublicKey pgpPublicKey = new PgpPublicKey(key);
|
||||
IList list = ((pgpPublicKey.subSigs != null) ? pgpPublicKey.subSigs : pgpPublicKey.keySigs);
|
||||
int num = list.IndexOf(certification);
|
||||
bool flag = num >= 0;
|
||||
if (flag)
|
||||
{
|
||||
list.RemoveAt(num);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (string userId in key.GetUserIds())
|
||||
{
|
||||
foreach (object item in key.GetSignaturesForId(userId))
|
||||
{
|
||||
if (certification == item)
|
||||
{
|
||||
flag = true;
|
||||
pgpPublicKey = RemoveCertification(pgpPublicKey, userId, certification);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!flag)
|
||||
{
|
||||
foreach (PgpUserAttributeSubpacketVector userAttribute in key.GetUserAttributes())
|
||||
{
|
||||
foreach (object item2 in key.GetSignaturesForUserAttribute(userAttribute))
|
||||
{
|
||||
if (certification == item2)
|
||||
{
|
||||
flag = true;
|
||||
pgpPublicKey = RemoveCertification(pgpPublicKey, userAttribute, certification);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return pgpPublicKey;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Asn1.X9;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Generators;
|
||||
using Org.BouncyCastle.Crypto.IO;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Math.EC;
|
||||
using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Utilities.IO;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpPublicKeyEncryptedData : PgpEncryptedData
|
||||
{
|
||||
private PublicKeyEncSessionPacket keyData;
|
||||
|
||||
public long KeyId => keyData.KeyId;
|
||||
|
||||
internal PgpPublicKeyEncryptedData(PublicKeyEncSessionPacket keyData, InputStreamPacket encData)
|
||||
: base(encData)
|
||||
{
|
||||
this.keyData = keyData;
|
||||
}
|
||||
|
||||
private static IBufferedCipher GetKeyCipher(PublicKeyAlgorithmTag algorithm)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (algorithm)
|
||||
{
|
||||
case PublicKeyAlgorithmTag.RsaGeneral:
|
||||
case PublicKeyAlgorithmTag.RsaEncrypt:
|
||||
return CipherUtilities.GetCipher("RSA//PKCS1Padding");
|
||||
case PublicKeyAlgorithmTag.ElGamalEncrypt:
|
||||
case PublicKeyAlgorithmTag.ElGamalGeneral:
|
||||
return CipherUtilities.GetCipher("ElGamal/ECB/PKCS1Padding");
|
||||
default:
|
||||
throw new PgpException("unknown asymmetric algorithm: " + algorithm);
|
||||
}
|
||||
}
|
||||
catch (PgpException ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw new PgpException("Exception creating cipher", exception);
|
||||
}
|
||||
}
|
||||
|
||||
private bool ConfirmCheckSum(byte[] sessionInfo)
|
||||
{
|
||||
int num = 0;
|
||||
for (int i = 1; i != sessionInfo.Length - 2; i++)
|
||||
{
|
||||
num += sessionInfo[i] & 0xFF;
|
||||
}
|
||||
if (sessionInfo[^2] == (byte)(num >> 8))
|
||||
{
|
||||
return sessionInfo[^1] == (byte)num;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public SymmetricKeyAlgorithmTag GetSymmetricAlgorithm(PgpPrivateKey privKey)
|
||||
{
|
||||
byte[] array = RecoverSessionData(privKey);
|
||||
return (SymmetricKeyAlgorithmTag)array[0];
|
||||
}
|
||||
|
||||
public Stream GetDataStream(PgpPrivateKey privKey)
|
||||
{
|
||||
byte[] array = RecoverSessionData(privKey);
|
||||
if (!ConfirmCheckSum(array))
|
||||
{
|
||||
throw new PgpKeyValidationException("key checksum failed");
|
||||
}
|
||||
SymmetricKeyAlgorithmTag symmetricKeyAlgorithmTag = (SymmetricKeyAlgorithmTag)array[0];
|
||||
if (symmetricKeyAlgorithmTag == SymmetricKeyAlgorithmTag.Null)
|
||||
{
|
||||
return encData.GetInputStream();
|
||||
}
|
||||
string symmetricCipherName = PgpUtilities.GetSymmetricCipherName(symmetricKeyAlgorithmTag);
|
||||
string text = symmetricCipherName;
|
||||
IBufferedCipher cipher;
|
||||
try
|
||||
{
|
||||
text = ((!(encData is SymmetricEncIntegrityPacket)) ? (text + "/OpenPGPCFB/NoPadding") : (text + "/CFB/NoPadding"));
|
||||
cipher = CipherUtilities.GetCipher(text);
|
||||
}
|
||||
catch (PgpException ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw new PgpException("exception creating cipher", exception);
|
||||
}
|
||||
try
|
||||
{
|
||||
KeyParameter parameters = ParameterUtilities.CreateKeyParameter(symmetricCipherName, array, 1, array.Length - 3);
|
||||
byte[] array2 = new byte[cipher.GetBlockSize()];
|
||||
cipher.Init(forEncryption: false, new ParametersWithIV(parameters, array2));
|
||||
encStream = BcpgInputStream.Wrap(new CipherStream(encData.GetInputStream(), cipher, null));
|
||||
if (encData is SymmetricEncIntegrityPacket)
|
||||
{
|
||||
truncStream = new TruncatedStream(encStream);
|
||||
string digestName = PgpUtilities.GetDigestName(HashAlgorithmTag.Sha1);
|
||||
IDigest digest = DigestUtilities.GetDigest(digestName);
|
||||
encStream = new DigestStream(truncStream, digest, null);
|
||||
}
|
||||
if (Streams.ReadFully(encStream, array2, 0, array2.Length) < array2.Length)
|
||||
{
|
||||
throw new EndOfStreamException("unexpected end of stream.");
|
||||
}
|
||||
int num = encStream.ReadByte();
|
||||
int num2 = encStream.ReadByte();
|
||||
if (num < 0 || num2 < 0)
|
||||
{
|
||||
throw new EndOfStreamException("unexpected end of stream.");
|
||||
}
|
||||
return encStream;
|
||||
}
|
||||
catch (PgpException ex2)
|
||||
{
|
||||
throw ex2;
|
||||
}
|
||||
catch (Exception exception2)
|
||||
{
|
||||
throw new PgpException("Exception starting decryption", exception2);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] RecoverSessionData(PgpPrivateKey privKey)
|
||||
{
|
||||
byte[][] encSessionKey = keyData.GetEncSessionKey();
|
||||
if (keyData.Algorithm == PublicKeyAlgorithmTag.EC)
|
||||
{
|
||||
ECDHPublicBcpgKey eCDHPublicBcpgKey = (ECDHPublicBcpgKey)privKey.PublicKeyPacket.Key;
|
||||
X9ECParameters x9ECParameters = ECKeyPairGenerator.FindECCurveByOid(eCDHPublicBcpgKey.CurveOid);
|
||||
byte[] array = encSessionKey[0];
|
||||
int num = (((array[0] & 0xFF) << 8) + (array[1] & 0xFF) + 7) / 8;
|
||||
byte[] array2 = new byte[num];
|
||||
Array.Copy(array, 2, array2, 0, num);
|
||||
byte[] array3 = new byte[array[num + 2]];
|
||||
Array.Copy(array, 2 + num + 1, array3, 0, array3.Length);
|
||||
ECPoint eCPoint = x9ECParameters.Curve.DecodePoint(array2);
|
||||
ECPrivateKeyParameters eCPrivateKeyParameters = (ECPrivateKeyParameters)privKey.Key;
|
||||
ECPoint s = eCPoint.Multiply(eCPrivateKeyParameters.D).Normalize();
|
||||
KeyParameter parameters = new KeyParameter(Rfc6637Utilities.CreateKey(privKey.PublicKeyPacket, s));
|
||||
IWrapper wrapper = PgpUtilities.CreateWrapper(eCDHPublicBcpgKey.SymmetricKeyAlgorithm);
|
||||
wrapper.Init(forWrapping: false, parameters);
|
||||
return PgpPad.UnpadSessionData(wrapper.Unwrap(array3, 0, array3.Length));
|
||||
}
|
||||
IBufferedCipher keyCipher = GetKeyCipher(keyData.Algorithm);
|
||||
try
|
||||
{
|
||||
keyCipher.Init(forEncryption: false, privKey.Key);
|
||||
}
|
||||
catch (InvalidKeyException exception)
|
||||
{
|
||||
throw new PgpException("error setting asymmetric cipher", exception);
|
||||
}
|
||||
if (keyData.Algorithm == PublicKeyAlgorithmTag.RsaEncrypt || keyData.Algorithm == PublicKeyAlgorithmTag.RsaGeneral)
|
||||
{
|
||||
byte[] array4 = encSessionKey[0];
|
||||
keyCipher.ProcessBytes(array4, 2, array4.Length - 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
ElGamalPrivateKeyParameters elGamalPrivateKeyParameters = (ElGamalPrivateKeyParameters)privKey.Key;
|
||||
int size = (elGamalPrivateKeyParameters.Parameters.P.BitLength + 7) / 8;
|
||||
ProcessEncodedMpi(keyCipher, size, encSessionKey[0]);
|
||||
ProcessEncodedMpi(keyCipher, size, encSessionKey[1]);
|
||||
}
|
||||
try
|
||||
{
|
||||
return keyCipher.DoFinal();
|
||||
}
|
||||
catch (Exception exception2)
|
||||
{
|
||||
throw new PgpException("exception decrypting secret key", exception2);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ProcessEncodedMpi(IBufferedCipher cipher, int size, byte[] mpiEnc)
|
||||
{
|
||||
if (mpiEnc.Length - 2 > size)
|
||||
{
|
||||
cipher.ProcessBytes(mpiEnc, 3, mpiEnc.Length - 3);
|
||||
return;
|
||||
}
|
||||
byte[] array = new byte[size];
|
||||
Array.Copy(mpiEnc, 2, array, array.Length - (mpiEnc.Length - 2), mpiEnc.Length - 2);
|
||||
cipher.ProcessBytes(array, 0, array.Length);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
using Org.BouncyCastle.Utilities.Collections;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpPublicKeyRing : PgpKeyRing
|
||||
{
|
||||
private readonly IList keys;
|
||||
|
||||
public PgpPublicKeyRing(byte[] encoding)
|
||||
: this(new MemoryStream(encoding, writable: false))
|
||||
{
|
||||
}
|
||||
|
||||
internal PgpPublicKeyRing(IList pubKeys)
|
||||
{
|
||||
keys = pubKeys;
|
||||
}
|
||||
|
||||
public PgpPublicKeyRing(Stream inputStream)
|
||||
{
|
||||
keys = Platform.CreateArrayList();
|
||||
BcpgInputStream bcpgInputStream = BcpgInputStream.Wrap(inputStream);
|
||||
PacketTag packetTag = bcpgInputStream.NextPacketTag();
|
||||
if (packetTag != PacketTag.PublicKey && packetTag != PacketTag.PublicSubkey)
|
||||
{
|
||||
int num = (int)packetTag;
|
||||
throw new IOException("public key ring doesn't start with public key tag: tag 0x" + num.ToString("X"));
|
||||
}
|
||||
PublicKeyPacket publicPk = (PublicKeyPacket)bcpgInputStream.ReadPacket();
|
||||
TrustPacket trustPk = PgpKeyRing.ReadOptionalTrustPacket(bcpgInputStream);
|
||||
IList keySigs = PgpKeyRing.ReadSignaturesAndTrust(bcpgInputStream);
|
||||
PgpKeyRing.ReadUserIDs(bcpgInputStream, out var ids, out var idTrusts, out var idSigs);
|
||||
keys.Add(new PgpPublicKey(publicPk, trustPk, keySigs, ids, idTrusts, idSigs));
|
||||
while (bcpgInputStream.NextPacketTag() == PacketTag.PublicSubkey)
|
||||
{
|
||||
keys.Add(ReadSubkey(bcpgInputStream));
|
||||
}
|
||||
}
|
||||
|
||||
public virtual PgpPublicKey GetPublicKey()
|
||||
{
|
||||
return (PgpPublicKey)keys[0];
|
||||
}
|
||||
|
||||
public virtual PgpPublicKey GetPublicKey(long keyId)
|
||||
{
|
||||
foreach (PgpPublicKey key in keys)
|
||||
{
|
||||
if (keyId == key.KeyId)
|
||||
{
|
||||
return key;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual IEnumerable GetPublicKeys()
|
||||
{
|
||||
return new EnumerableProxy(keys);
|
||||
}
|
||||
|
||||
public virtual byte[] GetEncoded()
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
Encode(memoryStream);
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
|
||||
public virtual void Encode(Stream outStr)
|
||||
{
|
||||
if (outStr == null)
|
||||
{
|
||||
throw new ArgumentNullException("outStr");
|
||||
}
|
||||
foreach (PgpPublicKey key in keys)
|
||||
{
|
||||
key.Encode(outStr);
|
||||
}
|
||||
}
|
||||
|
||||
public static PgpPublicKeyRing InsertPublicKey(PgpPublicKeyRing pubRing, PgpPublicKey pubKey)
|
||||
{
|
||||
IList list = Platform.CreateArrayList(pubRing.keys);
|
||||
bool flag = false;
|
||||
bool flag2 = false;
|
||||
for (int i = 0; i != list.Count; i++)
|
||||
{
|
||||
PgpPublicKey pgpPublicKey = (PgpPublicKey)list[i];
|
||||
if (pgpPublicKey.KeyId == pubKey.KeyId)
|
||||
{
|
||||
flag = true;
|
||||
list[i] = pubKey;
|
||||
}
|
||||
if (pgpPublicKey.IsMasterKey)
|
||||
{
|
||||
flag2 = true;
|
||||
}
|
||||
}
|
||||
if (!flag)
|
||||
{
|
||||
if (pubKey.IsMasterKey)
|
||||
{
|
||||
if (flag2)
|
||||
{
|
||||
throw new ArgumentException("cannot add a master key to a ring that already has one");
|
||||
}
|
||||
list.Insert(0, pubKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
list.Add(pubKey);
|
||||
}
|
||||
}
|
||||
return new PgpPublicKeyRing(list);
|
||||
}
|
||||
|
||||
public static PgpPublicKeyRing RemovePublicKey(PgpPublicKeyRing pubRing, PgpPublicKey pubKey)
|
||||
{
|
||||
IList list = Platform.CreateArrayList(pubRing.keys);
|
||||
bool flag = false;
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
PgpPublicKey pgpPublicKey = (PgpPublicKey)list[i];
|
||||
if (pgpPublicKey.KeyId == pubKey.KeyId)
|
||||
{
|
||||
flag = true;
|
||||
list.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
if (!flag)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return new PgpPublicKeyRing(list);
|
||||
}
|
||||
|
||||
internal static PgpPublicKey ReadSubkey(BcpgInputStream bcpgInput)
|
||||
{
|
||||
PublicKeyPacket publicPk = (PublicKeyPacket)bcpgInput.ReadPacket();
|
||||
TrustPacket trustPk = PgpKeyRing.ReadOptionalTrustPacket(bcpgInput);
|
||||
IList sigs = PgpKeyRing.ReadSignaturesAndTrust(bcpgInput);
|
||||
return new PgpPublicKey(publicPk, trustPk, sigs);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
using Org.BouncyCastle.Utilities.Collections;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpPublicKeyRingBundle
|
||||
{
|
||||
private readonly IDictionary pubRings;
|
||||
|
||||
private readonly IList order;
|
||||
|
||||
[Obsolete("Use 'Count' property instead")]
|
||||
public int Size => order.Count;
|
||||
|
||||
public int Count => order.Count;
|
||||
|
||||
private PgpPublicKeyRingBundle(IDictionary pubRings, IList order)
|
||||
{
|
||||
this.pubRings = pubRings;
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
public PgpPublicKeyRingBundle(byte[] encoding)
|
||||
: this(new MemoryStream(encoding, writable: false))
|
||||
{
|
||||
}
|
||||
|
||||
public PgpPublicKeyRingBundle(Stream inputStream)
|
||||
: this(new PgpObjectFactory(inputStream).AllPgpObjects())
|
||||
{
|
||||
}
|
||||
|
||||
public PgpPublicKeyRingBundle(IEnumerable e)
|
||||
{
|
||||
pubRings = Platform.CreateHashtable();
|
||||
order = Platform.CreateArrayList();
|
||||
foreach (object item in e)
|
||||
{
|
||||
if (!(item is PgpPublicKeyRing pgpPublicKeyRing))
|
||||
{
|
||||
throw new PgpException(Platform.GetTypeName(item) + " found where PgpPublicKeyRing expected");
|
||||
}
|
||||
long keyId = pgpPublicKeyRing.GetPublicKey().KeyId;
|
||||
pubRings.Add(keyId, pgpPublicKeyRing);
|
||||
order.Add(keyId);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable GetKeyRings()
|
||||
{
|
||||
return new EnumerableProxy(pubRings.Values);
|
||||
}
|
||||
|
||||
public IEnumerable GetKeyRings(string userId)
|
||||
{
|
||||
return GetKeyRings(userId, matchPartial: false, ignoreCase: false);
|
||||
}
|
||||
|
||||
public IEnumerable GetKeyRings(string userId, bool matchPartial)
|
||||
{
|
||||
return GetKeyRings(userId, matchPartial, ignoreCase: false);
|
||||
}
|
||||
|
||||
public IEnumerable GetKeyRings(string userId, bool matchPartial, bool ignoreCase)
|
||||
{
|
||||
IList list = Platform.CreateArrayList();
|
||||
if (ignoreCase)
|
||||
{
|
||||
userId = Platform.ToUpperInvariant(userId);
|
||||
}
|
||||
foreach (PgpPublicKeyRing keyRing in GetKeyRings())
|
||||
{
|
||||
foreach (string userId2 in keyRing.GetPublicKey().GetUserIds())
|
||||
{
|
||||
string text2 = userId2;
|
||||
if (ignoreCase)
|
||||
{
|
||||
text2 = Platform.ToUpperInvariant(text2);
|
||||
}
|
||||
if (matchPartial)
|
||||
{
|
||||
if (Platform.IndexOf(text2, userId) > -1)
|
||||
{
|
||||
list.Add(keyRing);
|
||||
}
|
||||
}
|
||||
else if (text2.Equals(userId))
|
||||
{
|
||||
list.Add(keyRing);
|
||||
}
|
||||
}
|
||||
}
|
||||
return new EnumerableProxy(list);
|
||||
}
|
||||
|
||||
public PgpPublicKey GetPublicKey(long keyId)
|
||||
{
|
||||
foreach (PgpPublicKeyRing keyRing in GetKeyRings())
|
||||
{
|
||||
PgpPublicKey publicKey = keyRing.GetPublicKey(keyId);
|
||||
if (publicKey != null)
|
||||
{
|
||||
return publicKey;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public PgpPublicKeyRing GetPublicKeyRing(long keyId)
|
||||
{
|
||||
if (pubRings.Contains(keyId))
|
||||
{
|
||||
return (PgpPublicKeyRing)pubRings[keyId];
|
||||
}
|
||||
foreach (PgpPublicKeyRing keyRing in GetKeyRings())
|
||||
{
|
||||
PgpPublicKey publicKey = keyRing.GetPublicKey(keyId);
|
||||
if (publicKey != null)
|
||||
{
|
||||
return keyRing;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool Contains(long keyID)
|
||||
{
|
||||
return GetPublicKey(keyID) != null;
|
||||
}
|
||||
|
||||
public byte[] GetEncoded()
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
Encode(memoryStream);
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
|
||||
public void Encode(Stream outStr)
|
||||
{
|
||||
BcpgOutputStream outStr2 = BcpgOutputStream.Wrap(outStr);
|
||||
foreach (object item in order)
|
||||
{
|
||||
long num = (long)item;
|
||||
PgpPublicKeyRing pgpPublicKeyRing = (PgpPublicKeyRing)pubRings[num];
|
||||
pgpPublicKeyRing.Encode(outStr2);
|
||||
}
|
||||
}
|
||||
|
||||
public static PgpPublicKeyRingBundle AddPublicKeyRing(PgpPublicKeyRingBundle bundle, PgpPublicKeyRing publicKeyRing)
|
||||
{
|
||||
long keyId = publicKeyRing.GetPublicKey().KeyId;
|
||||
if (bundle.pubRings.Contains(keyId))
|
||||
{
|
||||
throw new ArgumentException("Bundle already contains a key with a keyId for the passed in ring.");
|
||||
}
|
||||
IDictionary dictionary = Platform.CreateHashtable(bundle.pubRings);
|
||||
IList list = Platform.CreateArrayList(bundle.order);
|
||||
dictionary[keyId] = publicKeyRing;
|
||||
list.Add(keyId);
|
||||
return new PgpPublicKeyRingBundle(dictionary, list);
|
||||
}
|
||||
|
||||
public static PgpPublicKeyRingBundle RemovePublicKeyRing(PgpPublicKeyRingBundle bundle, PgpPublicKeyRing publicKeyRing)
|
||||
{
|
||||
long keyId = publicKeyRing.GetPublicKey().KeyId;
|
||||
if (!bundle.pubRings.Contains(keyId))
|
||||
{
|
||||
throw new ArgumentException("Bundle does not contain a key with a keyId for the passed in ring.");
|
||||
}
|
||||
IDictionary dictionary = Platform.CreateHashtable(bundle.pubRings);
|
||||
IList list = Platform.CreateArrayList(bundle.order);
|
||||
dictionary.Remove(keyId);
|
||||
list.Remove(keyId);
|
||||
return new PgpPublicKeyRingBundle(dictionary, list);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,758 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Asn1.X9;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Math;
|
||||
using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpSecretKey
|
||||
{
|
||||
private readonly SecretKeyPacket secret;
|
||||
|
||||
private readonly PgpPublicKey pub;
|
||||
|
||||
public bool IsSigningKey
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (pub.Algorithm)
|
||||
{
|
||||
case PublicKeyAlgorithmTag.RsaGeneral:
|
||||
case PublicKeyAlgorithmTag.RsaSign:
|
||||
case PublicKeyAlgorithmTag.Dsa:
|
||||
case PublicKeyAlgorithmTag.ECDsa:
|
||||
case PublicKeyAlgorithmTag.ElGamalGeneral:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsMasterKey => pub.IsMasterKey;
|
||||
|
||||
public bool IsPrivateKeyEmpty
|
||||
{
|
||||
get
|
||||
{
|
||||
byte[] secretKeyData = secret.GetSecretKeyData();
|
||||
if (secretKeyData != null)
|
||||
{
|
||||
return secretKeyData.Length < 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public SymmetricKeyAlgorithmTag KeyEncryptionAlgorithm => secret.EncAlgorithm;
|
||||
|
||||
public long KeyId => pub.KeyId;
|
||||
|
||||
public int S2kUsage => secret.S2kUsage;
|
||||
|
||||
public S2k S2k => secret.S2k;
|
||||
|
||||
public PgpPublicKey PublicKey => pub;
|
||||
|
||||
public IEnumerable UserIds => pub.GetUserIds();
|
||||
|
||||
public IEnumerable UserAttributes => pub.GetUserAttributes();
|
||||
|
||||
internal PgpSecretKey(SecretKeyPacket secret, PgpPublicKey pub)
|
||||
{
|
||||
this.secret = secret;
|
||||
this.pub = pub;
|
||||
}
|
||||
|
||||
internal PgpSecretKey(PgpPrivateKey privKey, PgpPublicKey pubKey, SymmetricKeyAlgorithmTag encAlgorithm, byte[] rawPassPhrase, bool clearPassPhrase, bool useSha1, SecureRandom rand, bool isMasterKey)
|
||||
{
|
||||
pub = pubKey;
|
||||
BcpgObject bcpgObject;
|
||||
switch (pubKey.Algorithm)
|
||||
{
|
||||
case PublicKeyAlgorithmTag.RsaGeneral:
|
||||
case PublicKeyAlgorithmTag.RsaEncrypt:
|
||||
case PublicKeyAlgorithmTag.RsaSign:
|
||||
{
|
||||
RsaPrivateCrtKeyParameters rsaPrivateCrtKeyParameters = (RsaPrivateCrtKeyParameters)privKey.Key;
|
||||
bcpgObject = new RsaSecretBcpgKey(rsaPrivateCrtKeyParameters.Exponent, rsaPrivateCrtKeyParameters.P, rsaPrivateCrtKeyParameters.Q);
|
||||
break;
|
||||
}
|
||||
case PublicKeyAlgorithmTag.Dsa:
|
||||
{
|
||||
DsaPrivateKeyParameters dsaPrivateKeyParameters = (DsaPrivateKeyParameters)privKey.Key;
|
||||
bcpgObject = new DsaSecretBcpgKey(dsaPrivateKeyParameters.X);
|
||||
break;
|
||||
}
|
||||
case PublicKeyAlgorithmTag.EC:
|
||||
case PublicKeyAlgorithmTag.ECDsa:
|
||||
{
|
||||
ECPrivateKeyParameters eCPrivateKeyParameters = (ECPrivateKeyParameters)privKey.Key;
|
||||
bcpgObject = new ECSecretBcpgKey(eCPrivateKeyParameters.D);
|
||||
break;
|
||||
}
|
||||
case PublicKeyAlgorithmTag.ElGamalEncrypt:
|
||||
case PublicKeyAlgorithmTag.ElGamalGeneral:
|
||||
{
|
||||
ElGamalPrivateKeyParameters elGamalPrivateKeyParameters = (ElGamalPrivateKeyParameters)privKey.Key;
|
||||
bcpgObject = new ElGamalSecretBcpgKey(elGamalPrivateKeyParameters.X);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new PgpException("unknown key class");
|
||||
}
|
||||
try
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
BcpgOutputStream bcpgOutputStream = new BcpgOutputStream(memoryStream);
|
||||
bcpgOutputStream.WriteObject(bcpgObject);
|
||||
byte[] array = memoryStream.ToArray();
|
||||
byte[] b = Checksum(useSha1, array, array.Length);
|
||||
array = Arrays.Concatenate(array, b);
|
||||
if (encAlgorithm == SymmetricKeyAlgorithmTag.Null)
|
||||
{
|
||||
if (isMasterKey)
|
||||
{
|
||||
secret = new SecretKeyPacket(pub.publicPk, encAlgorithm, null, null, array);
|
||||
}
|
||||
else
|
||||
{
|
||||
secret = new SecretSubkeyPacket(pub.publicPk, encAlgorithm, null, null, array);
|
||||
}
|
||||
return;
|
||||
}
|
||||
S2k s2k;
|
||||
byte[] iv;
|
||||
byte[] secKeyData = ((pub.Version < 4) ? EncryptKeyDataV3(array, encAlgorithm, rawPassPhrase, clearPassPhrase, rand, out s2k, out iv) : EncryptKeyDataV4(array, encAlgorithm, HashAlgorithmTag.Sha1, rawPassPhrase, clearPassPhrase, rand, out s2k, out iv));
|
||||
int s2kUsage = (useSha1 ? 254 : 255);
|
||||
if (isMasterKey)
|
||||
{
|
||||
secret = new SecretKeyPacket(pub.publicPk, encAlgorithm, s2kUsage, s2k, iv, secKeyData);
|
||||
}
|
||||
else
|
||||
{
|
||||
secret = new SecretSubkeyPacket(pub.publicPk, encAlgorithm, s2kUsage, s2k, iv, secKeyData);
|
||||
}
|
||||
}
|
||||
catch (PgpException ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw new PgpException("Exception encrypting key", exception);
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("Use the constructor taking an explicit 'useSha1' parameter instead")]
|
||||
public PgpSecretKey(int certificationLevel, PgpKeyPair keyPair, string id, SymmetricKeyAlgorithmTag encAlgorithm, char[] passPhrase, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, SecureRandom rand)
|
||||
: this(certificationLevel, keyPair, id, encAlgorithm, passPhrase, useSha1: false, hashedPackets, unhashedPackets, rand)
|
||||
{
|
||||
}
|
||||
|
||||
public PgpSecretKey(int certificationLevel, PgpKeyPair keyPair, string id, SymmetricKeyAlgorithmTag encAlgorithm, char[] passPhrase, bool useSha1, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, SecureRandom rand)
|
||||
: this(certificationLevel, keyPair, id, encAlgorithm, utf8PassPhrase: false, passPhrase, useSha1, hashedPackets, unhashedPackets, rand)
|
||||
{
|
||||
}
|
||||
|
||||
public PgpSecretKey(int certificationLevel, PgpKeyPair keyPair, string id, SymmetricKeyAlgorithmTag encAlgorithm, bool utf8PassPhrase, char[] passPhrase, bool useSha1, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, SecureRandom rand)
|
||||
: this(certificationLevel, keyPair, id, encAlgorithm, PgpUtilities.EncodePassPhrase(passPhrase, utf8PassPhrase), clearPassPhrase: true, useSha1, hashedPackets, unhashedPackets, rand)
|
||||
{
|
||||
}
|
||||
|
||||
public PgpSecretKey(int certificationLevel, PgpKeyPair keyPair, string id, SymmetricKeyAlgorithmTag encAlgorithm, byte[] rawPassPhrase, bool useSha1, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, SecureRandom rand)
|
||||
: this(certificationLevel, keyPair, id, encAlgorithm, rawPassPhrase, clearPassPhrase: false, useSha1, hashedPackets, unhashedPackets, rand)
|
||||
{
|
||||
}
|
||||
|
||||
internal PgpSecretKey(int certificationLevel, PgpKeyPair keyPair, string id, SymmetricKeyAlgorithmTag encAlgorithm, byte[] rawPassPhrase, bool clearPassPhrase, bool useSha1, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, SecureRandom rand)
|
||||
: this(keyPair.PrivateKey, CertifiedPublicKey(certificationLevel, keyPair, id, hashedPackets, unhashedPackets), encAlgorithm, rawPassPhrase, clearPassPhrase, useSha1, rand, isMasterKey: true)
|
||||
{
|
||||
}
|
||||
|
||||
public PgpSecretKey(int certificationLevel, PgpKeyPair keyPair, string id, SymmetricKeyAlgorithmTag encAlgorithm, HashAlgorithmTag hashAlgorithm, char[] passPhrase, bool useSha1, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, SecureRandom rand)
|
||||
: this(certificationLevel, keyPair, id, encAlgorithm, hashAlgorithm, utf8PassPhrase: false, passPhrase, useSha1, hashedPackets, unhashedPackets, rand)
|
||||
{
|
||||
}
|
||||
|
||||
public PgpSecretKey(int certificationLevel, PgpKeyPair keyPair, string id, SymmetricKeyAlgorithmTag encAlgorithm, HashAlgorithmTag hashAlgorithm, bool utf8PassPhrase, char[] passPhrase, bool useSha1, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, SecureRandom rand)
|
||||
: this(certificationLevel, keyPair, id, encAlgorithm, hashAlgorithm, PgpUtilities.EncodePassPhrase(passPhrase, utf8PassPhrase), clearPassPhrase: true, useSha1, hashedPackets, unhashedPackets, rand)
|
||||
{
|
||||
}
|
||||
|
||||
public PgpSecretKey(int certificationLevel, PgpKeyPair keyPair, string id, SymmetricKeyAlgorithmTag encAlgorithm, HashAlgorithmTag hashAlgorithm, byte[] rawPassPhrase, bool useSha1, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, SecureRandom rand)
|
||||
: this(certificationLevel, keyPair, id, encAlgorithm, hashAlgorithm, rawPassPhrase, clearPassPhrase: false, useSha1, hashedPackets, unhashedPackets, rand)
|
||||
{
|
||||
}
|
||||
|
||||
internal PgpSecretKey(int certificationLevel, PgpKeyPair keyPair, string id, SymmetricKeyAlgorithmTag encAlgorithm, HashAlgorithmTag hashAlgorithm, byte[] rawPassPhrase, bool clearPassPhrase, bool useSha1, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, SecureRandom rand)
|
||||
: this(keyPair.PrivateKey, CertifiedPublicKey(certificationLevel, keyPair, id, hashedPackets, unhashedPackets, hashAlgorithm), encAlgorithm, rawPassPhrase, clearPassPhrase, useSha1, rand, isMasterKey: true)
|
||||
{
|
||||
}
|
||||
|
||||
private static PgpPublicKey CertifiedPublicKey(int certificationLevel, PgpKeyPair keyPair, string id, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets)
|
||||
{
|
||||
PgpSignatureGenerator pgpSignatureGenerator;
|
||||
try
|
||||
{
|
||||
pgpSignatureGenerator = new PgpSignatureGenerator(keyPair.PublicKey.Algorithm, HashAlgorithmTag.Sha1);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new PgpException("Creating signature generator: " + ex.Message, ex);
|
||||
}
|
||||
pgpSignatureGenerator.InitSign(certificationLevel, keyPair.PrivateKey);
|
||||
pgpSignatureGenerator.SetHashedSubpackets(hashedPackets);
|
||||
pgpSignatureGenerator.SetUnhashedSubpackets(unhashedPackets);
|
||||
try
|
||||
{
|
||||
PgpSignature certification = pgpSignatureGenerator.GenerateCertification(id, keyPair.PublicKey);
|
||||
return PgpPublicKey.AddCertification(keyPair.PublicKey, id, certification);
|
||||
}
|
||||
catch (Exception ex2)
|
||||
{
|
||||
throw new PgpException("Exception doing certification: " + ex2.Message, ex2);
|
||||
}
|
||||
}
|
||||
|
||||
private static PgpPublicKey CertifiedPublicKey(int certificationLevel, PgpKeyPair keyPair, string id, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, HashAlgorithmTag hashAlgorithm)
|
||||
{
|
||||
PgpSignatureGenerator pgpSignatureGenerator;
|
||||
try
|
||||
{
|
||||
pgpSignatureGenerator = new PgpSignatureGenerator(keyPair.PublicKey.Algorithm, hashAlgorithm);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new PgpException("Creating signature generator: " + ex.Message, ex);
|
||||
}
|
||||
pgpSignatureGenerator.InitSign(certificationLevel, keyPair.PrivateKey);
|
||||
pgpSignatureGenerator.SetHashedSubpackets(hashedPackets);
|
||||
pgpSignatureGenerator.SetUnhashedSubpackets(unhashedPackets);
|
||||
try
|
||||
{
|
||||
PgpSignature certification = pgpSignatureGenerator.GenerateCertification(id, keyPair.PublicKey);
|
||||
return PgpPublicKey.AddCertification(keyPair.PublicKey, id, certification);
|
||||
}
|
||||
catch (Exception ex2)
|
||||
{
|
||||
throw new PgpException("Exception doing certification: " + ex2.Message, ex2);
|
||||
}
|
||||
}
|
||||
|
||||
public PgpSecretKey(int certificationLevel, PublicKeyAlgorithmTag algorithm, AsymmetricKeyParameter pubKey, AsymmetricKeyParameter privKey, DateTime time, string id, SymmetricKeyAlgorithmTag encAlgorithm, char[] passPhrase, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, SecureRandom rand)
|
||||
: this(certificationLevel, new PgpKeyPair(algorithm, pubKey, privKey, time), id, encAlgorithm, passPhrase, useSha1: false, hashedPackets, unhashedPackets, rand)
|
||||
{
|
||||
}
|
||||
|
||||
public PgpSecretKey(int certificationLevel, PublicKeyAlgorithmTag algorithm, AsymmetricKeyParameter pubKey, AsymmetricKeyParameter privKey, DateTime time, string id, SymmetricKeyAlgorithmTag encAlgorithm, char[] passPhrase, bool useSha1, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, SecureRandom rand)
|
||||
: this(certificationLevel, new PgpKeyPair(algorithm, pubKey, privKey, time), id, encAlgorithm, passPhrase, useSha1, hashedPackets, unhashedPackets, rand)
|
||||
{
|
||||
}
|
||||
|
||||
private byte[] ExtractKeyData(byte[] rawPassPhrase, bool clearPassPhrase)
|
||||
{
|
||||
SymmetricKeyAlgorithmTag encAlgorithm = secret.EncAlgorithm;
|
||||
byte[] secretKeyData = secret.GetSecretKeyData();
|
||||
if (encAlgorithm == SymmetricKeyAlgorithmTag.Null)
|
||||
{
|
||||
return secretKeyData;
|
||||
}
|
||||
try
|
||||
{
|
||||
KeyParameter key = PgpUtilities.DoMakeKeyFromPassPhrase(secret.EncAlgorithm, secret.S2k, rawPassPhrase, clearPassPhrase);
|
||||
byte[] iV = secret.GetIV();
|
||||
byte[] array;
|
||||
if (secret.PublicKeyPacket.Version >= 4)
|
||||
{
|
||||
array = RecoverKeyData(encAlgorithm, "/CFB/NoPadding", key, iV, secretKeyData, 0, secretKeyData.Length);
|
||||
bool flag = secret.S2kUsage == 254;
|
||||
byte[] array2 = Checksum(flag, array, flag ? (array.Length - 20) : (array.Length - 2));
|
||||
for (int i = 0; i != array2.Length; i++)
|
||||
{
|
||||
if (array2[i] != array[array.Length - array2.Length + i])
|
||||
{
|
||||
throw new PgpException("Checksum mismatch at " + i + " of " + array2.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
array = new byte[secretKeyData.Length];
|
||||
iV = Arrays.Clone(iV);
|
||||
int num = 0;
|
||||
for (int j = 0; j != 4; j++)
|
||||
{
|
||||
int num2 = (((secretKeyData[num] << 8) | (secretKeyData[num + 1] & 0xFF)) + 7) / 8;
|
||||
array[num] = secretKeyData[num];
|
||||
array[num + 1] = secretKeyData[num + 1];
|
||||
num += 2;
|
||||
byte[] sourceArray = RecoverKeyData(encAlgorithm, "/CFB/NoPadding", key, iV, secretKeyData, num, num2);
|
||||
Array.Copy(sourceArray, 0, array, num, num2);
|
||||
num += num2;
|
||||
if (j != 3)
|
||||
{
|
||||
Array.Copy(secretKeyData, num - iV.Length, iV, 0, iV.Length);
|
||||
}
|
||||
}
|
||||
array[num] = secretKeyData[num];
|
||||
array[num + 1] = secretKeyData[num + 1];
|
||||
int num3 = ((secretKeyData[num] << 8) & 0xFF00) | (secretKeyData[num + 1] & 0xFF);
|
||||
int num4 = 0;
|
||||
for (int k = 0; k < num; k++)
|
||||
{
|
||||
num4 += array[k] & 0xFF;
|
||||
}
|
||||
num4 &= 0xFFFF;
|
||||
if (num4 != num3)
|
||||
{
|
||||
throw new PgpException("Checksum mismatch: passphrase wrong, expected " + num3.ToString("X") + " found " + num4.ToString("X"));
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
catch (PgpException ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw new PgpException("Exception decrypting key", exception);
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] RecoverKeyData(SymmetricKeyAlgorithmTag encAlgorithm, string modeAndPadding, KeyParameter key, byte[] iv, byte[] keyData, int keyOff, int keyLen)
|
||||
{
|
||||
IBufferedCipher cipher;
|
||||
try
|
||||
{
|
||||
string symmetricCipherName = PgpUtilities.GetSymmetricCipherName(encAlgorithm);
|
||||
cipher = CipherUtilities.GetCipher(symmetricCipherName + modeAndPadding);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw new PgpException("Exception creating cipher", exception);
|
||||
}
|
||||
cipher.Init(forEncryption: false, new ParametersWithIV(key, iv));
|
||||
return cipher.DoFinal(keyData, keyOff, keyLen);
|
||||
}
|
||||
|
||||
public PgpPrivateKey ExtractPrivateKey(char[] passPhrase)
|
||||
{
|
||||
return DoExtractPrivateKey(PgpUtilities.EncodePassPhrase(passPhrase, utf8: false), clearPassPhrase: true);
|
||||
}
|
||||
|
||||
public PgpPrivateKey ExtractPrivateKeyUtf8(char[] passPhrase)
|
||||
{
|
||||
return DoExtractPrivateKey(PgpUtilities.EncodePassPhrase(passPhrase, utf8: true), clearPassPhrase: true);
|
||||
}
|
||||
|
||||
public PgpPrivateKey ExtractPrivateKeyRaw(byte[] rawPassPhrase)
|
||||
{
|
||||
return DoExtractPrivateKey(rawPassPhrase, clearPassPhrase: false);
|
||||
}
|
||||
|
||||
internal PgpPrivateKey DoExtractPrivateKey(byte[] rawPassPhrase, bool clearPassPhrase)
|
||||
{
|
||||
if (IsPrivateKeyEmpty)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
PublicKeyPacket publicKeyPacket = secret.PublicKeyPacket;
|
||||
try
|
||||
{
|
||||
byte[] buffer = ExtractKeyData(rawPassPhrase, clearPassPhrase);
|
||||
BcpgInputStream bcpgIn = BcpgInputStream.Wrap(new MemoryStream(buffer, writable: false));
|
||||
AsymmetricKeyParameter privateKey;
|
||||
switch (publicKeyPacket.Algorithm)
|
||||
{
|
||||
case PublicKeyAlgorithmTag.RsaGeneral:
|
||||
case PublicKeyAlgorithmTag.RsaEncrypt:
|
||||
case PublicKeyAlgorithmTag.RsaSign:
|
||||
{
|
||||
RsaPublicBcpgKey rsaPublicBcpgKey = (RsaPublicBcpgKey)publicKeyPacket.Key;
|
||||
RsaSecretBcpgKey rsaSecretBcpgKey = new RsaSecretBcpgKey(bcpgIn);
|
||||
RsaPrivateCrtKeyParameters rsaPrivateCrtKeyParameters = new RsaPrivateCrtKeyParameters(rsaSecretBcpgKey.Modulus, rsaPublicBcpgKey.PublicExponent, rsaSecretBcpgKey.PrivateExponent, rsaSecretBcpgKey.PrimeP, rsaSecretBcpgKey.PrimeQ, rsaSecretBcpgKey.PrimeExponentP, rsaSecretBcpgKey.PrimeExponentQ, rsaSecretBcpgKey.CrtCoefficient);
|
||||
privateKey = rsaPrivateCrtKeyParameters;
|
||||
break;
|
||||
}
|
||||
case PublicKeyAlgorithmTag.Dsa:
|
||||
{
|
||||
DsaPublicBcpgKey dsaPublicBcpgKey = (DsaPublicBcpgKey)publicKeyPacket.Key;
|
||||
DsaSecretBcpgKey dsaSecretBcpgKey = new DsaSecretBcpgKey(bcpgIn);
|
||||
DsaParameters parameters2 = new DsaParameters(dsaPublicBcpgKey.P, dsaPublicBcpgKey.Q, dsaPublicBcpgKey.G);
|
||||
privateKey = new DsaPrivateKeyParameters(dsaSecretBcpgKey.X, parameters2);
|
||||
break;
|
||||
}
|
||||
case PublicKeyAlgorithmTag.EC:
|
||||
privateKey = GetECKey("ECDH", bcpgIn);
|
||||
break;
|
||||
case PublicKeyAlgorithmTag.ECDsa:
|
||||
privateKey = GetECKey("ECDSA", bcpgIn);
|
||||
break;
|
||||
case PublicKeyAlgorithmTag.ElGamalEncrypt:
|
||||
case PublicKeyAlgorithmTag.ElGamalGeneral:
|
||||
{
|
||||
ElGamalPublicBcpgKey elGamalPublicBcpgKey = (ElGamalPublicBcpgKey)publicKeyPacket.Key;
|
||||
ElGamalSecretBcpgKey elGamalSecretBcpgKey = new ElGamalSecretBcpgKey(bcpgIn);
|
||||
ElGamalParameters parameters = new ElGamalParameters(elGamalPublicBcpgKey.P, elGamalPublicBcpgKey.G);
|
||||
privateKey = new ElGamalPrivateKeyParameters(elGamalSecretBcpgKey.X, parameters);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new PgpException("unknown public key algorithm encountered");
|
||||
}
|
||||
return new PgpPrivateKey(KeyId, publicKeyPacket, privateKey);
|
||||
}
|
||||
catch (PgpException ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw new PgpException("Exception constructing key", exception);
|
||||
}
|
||||
}
|
||||
|
||||
private ECPrivateKeyParameters GetECKey(string algorithm, BcpgInputStream bcpgIn)
|
||||
{
|
||||
ECPublicBcpgKey eCPublicBcpgKey = (ECPublicBcpgKey)secret.PublicKeyPacket.Key;
|
||||
ECSecretBcpgKey eCSecretBcpgKey = new ECSecretBcpgKey(bcpgIn);
|
||||
return new ECPrivateKeyParameters(algorithm, eCSecretBcpgKey.X, eCPublicBcpgKey.CurveOid);
|
||||
}
|
||||
|
||||
private static byte[] Checksum(bool useSha1, byte[] bytes, int length)
|
||||
{
|
||||
if (useSha1)
|
||||
{
|
||||
try
|
||||
{
|
||||
IDigest digest = DigestUtilities.GetDigest("SHA1");
|
||||
digest.BlockUpdate(bytes, 0, length);
|
||||
return DigestUtilities.DoFinal(digest);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw new PgpException("Can't find SHA-1", exception);
|
||||
}
|
||||
}
|
||||
int num = 0;
|
||||
for (int i = 0; i != length; i++)
|
||||
{
|
||||
num += bytes[i];
|
||||
}
|
||||
return new byte[2]
|
||||
{
|
||||
(byte)(num >> 8),
|
||||
(byte)num
|
||||
};
|
||||
}
|
||||
|
||||
public byte[] GetEncoded()
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
Encode(memoryStream);
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
|
||||
public void Encode(Stream outStr)
|
||||
{
|
||||
BcpgOutputStream bcpgOutputStream = BcpgOutputStream.Wrap(outStr);
|
||||
bcpgOutputStream.WritePacket(secret);
|
||||
if (pub.trustPk != null)
|
||||
{
|
||||
bcpgOutputStream.WritePacket(pub.trustPk);
|
||||
}
|
||||
if (pub.subSigs == null)
|
||||
{
|
||||
foreach (PgpSignature keySig in pub.keySigs)
|
||||
{
|
||||
keySig.Encode(bcpgOutputStream);
|
||||
}
|
||||
for (int i = 0; i != pub.ids.Count; i++)
|
||||
{
|
||||
object obj = pub.ids[i];
|
||||
if (obj is string)
|
||||
{
|
||||
string id = (string)obj;
|
||||
bcpgOutputStream.WritePacket(new UserIdPacket(id));
|
||||
}
|
||||
else
|
||||
{
|
||||
PgpUserAttributeSubpacketVector pgpUserAttributeSubpacketVector = (PgpUserAttributeSubpacketVector)obj;
|
||||
bcpgOutputStream.WritePacket(new UserAttributePacket(pgpUserAttributeSubpacketVector.ToSubpacketArray()));
|
||||
}
|
||||
if (pub.idTrusts[i] != null)
|
||||
{
|
||||
bcpgOutputStream.WritePacket((ContainedPacket)pub.idTrusts[i]);
|
||||
}
|
||||
foreach (PgpSignature item in (IList)pub.idSigs[i])
|
||||
{
|
||||
item.Encode(bcpgOutputStream);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
foreach (PgpSignature subSig in pub.subSigs)
|
||||
{
|
||||
subSig.Encode(bcpgOutputStream);
|
||||
}
|
||||
}
|
||||
|
||||
public static PgpSecretKey CopyWithNewPassword(PgpSecretKey key, char[] oldPassPhrase, char[] newPassPhrase, SymmetricKeyAlgorithmTag newEncAlgorithm, SecureRandom rand)
|
||||
{
|
||||
return DoCopyWithNewPassword(key, PgpUtilities.EncodePassPhrase(oldPassPhrase, utf8: false), PgpUtilities.EncodePassPhrase(newPassPhrase, utf8: false), clearPassPhrase: true, newEncAlgorithm, rand);
|
||||
}
|
||||
|
||||
public static PgpSecretKey CopyWithNewPasswordUtf8(PgpSecretKey key, char[] oldPassPhrase, char[] newPassPhrase, SymmetricKeyAlgorithmTag newEncAlgorithm, SecureRandom rand)
|
||||
{
|
||||
return DoCopyWithNewPassword(key, PgpUtilities.EncodePassPhrase(oldPassPhrase, utf8: true), PgpUtilities.EncodePassPhrase(newPassPhrase, utf8: true), clearPassPhrase: true, newEncAlgorithm, rand);
|
||||
}
|
||||
|
||||
public static PgpSecretKey CopyWithNewPasswordRaw(PgpSecretKey key, byte[] rawOldPassPhrase, byte[] rawNewPassPhrase, SymmetricKeyAlgorithmTag newEncAlgorithm, SecureRandom rand)
|
||||
{
|
||||
return DoCopyWithNewPassword(key, rawOldPassPhrase, rawNewPassPhrase, clearPassPhrase: false, newEncAlgorithm, rand);
|
||||
}
|
||||
|
||||
internal static PgpSecretKey DoCopyWithNewPassword(PgpSecretKey key, byte[] rawOldPassPhrase, byte[] rawNewPassPhrase, bool clearPassPhrase, SymmetricKeyAlgorithmTag newEncAlgorithm, SecureRandom rand)
|
||||
{
|
||||
if (key.IsPrivateKeyEmpty)
|
||||
{
|
||||
throw new PgpException("no private key in this SecretKey - public key present only.");
|
||||
}
|
||||
byte[] array = key.ExtractKeyData(rawOldPassPhrase, clearPassPhrase);
|
||||
int num = key.secret.S2kUsage;
|
||||
byte[] iv = null;
|
||||
S2k s2k = null;
|
||||
PublicKeyPacket publicKeyPacket = key.secret.PublicKeyPacket;
|
||||
byte[] array2;
|
||||
if (newEncAlgorithm == SymmetricKeyAlgorithmTag.Null)
|
||||
{
|
||||
num = 0;
|
||||
if (key.secret.S2kUsage == 254)
|
||||
{
|
||||
array2 = new byte[array.Length - 18];
|
||||
Array.Copy(array, 0, array2, 0, array2.Length - 2);
|
||||
byte[] array3 = Checksum(useSha1: false, array2, array2.Length - 2);
|
||||
array2[^2] = array3[0];
|
||||
array2[^1] = array3[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
array2 = array;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (num == 0)
|
||||
{
|
||||
num = 255;
|
||||
}
|
||||
try
|
||||
{
|
||||
array2 = ((publicKeyPacket.Version < 4) ? EncryptKeyDataV3(array, newEncAlgorithm, rawNewPassPhrase, clearPassPhrase, rand, out s2k, out iv) : EncryptKeyDataV4(array, newEncAlgorithm, HashAlgorithmTag.Sha1, rawNewPassPhrase, clearPassPhrase, rand, out s2k, out iv));
|
||||
}
|
||||
catch (PgpException ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw new PgpException("Exception encrypting key", exception);
|
||||
}
|
||||
}
|
||||
SecretKeyPacket secretKeyPacket = ((!(key.secret is SecretSubkeyPacket)) ? new SecretKeyPacket(publicKeyPacket, newEncAlgorithm, num, s2k, iv, array2) : new SecretSubkeyPacket(publicKeyPacket, newEncAlgorithm, num, s2k, iv, array2));
|
||||
return new PgpSecretKey(secretKeyPacket, key.pub);
|
||||
}
|
||||
|
||||
public static PgpSecretKey ReplacePublicKey(PgpSecretKey secretKey, PgpPublicKey publicKey)
|
||||
{
|
||||
if (publicKey.KeyId != secretKey.KeyId)
|
||||
{
|
||||
throw new ArgumentException("KeyId's do not match");
|
||||
}
|
||||
return new PgpSecretKey(secretKey.secret, publicKey);
|
||||
}
|
||||
|
||||
private static byte[] EncryptKeyDataV3(byte[] rawKeyData, SymmetricKeyAlgorithmTag encAlgorithm, byte[] rawPassPhrase, bool clearPassPhrase, SecureRandom random, out S2k s2k, out byte[] iv)
|
||||
{
|
||||
s2k = null;
|
||||
iv = null;
|
||||
KeyParameter key = PgpUtilities.DoMakeKeyFromPassPhrase(encAlgorithm, s2k, rawPassPhrase, clearPassPhrase);
|
||||
byte[] array = new byte[rawKeyData.Length];
|
||||
int num = 0;
|
||||
for (int i = 0; i != 4; i++)
|
||||
{
|
||||
int num2 = (((rawKeyData[num] << 8) | (rawKeyData[num + 1] & 0xFF)) + 7) / 8;
|
||||
array[num] = rawKeyData[num];
|
||||
array[num + 1] = rawKeyData[num + 1];
|
||||
byte[] array2;
|
||||
if (i == 0)
|
||||
{
|
||||
array2 = EncryptData(encAlgorithm, key, rawKeyData, num + 2, num2, random, ref iv);
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] iv2 = Arrays.CopyOfRange(array, num - iv.Length, num);
|
||||
array2 = EncryptData(encAlgorithm, key, rawKeyData, num + 2, num2, random, ref iv2);
|
||||
}
|
||||
Array.Copy(array2, 0, array, num + 2, array2.Length);
|
||||
num += 2 + num2;
|
||||
}
|
||||
array[num] = rawKeyData[num];
|
||||
array[num + 1] = rawKeyData[num + 1];
|
||||
return array;
|
||||
}
|
||||
|
||||
private static byte[] EncryptKeyDataV4(byte[] rawKeyData, SymmetricKeyAlgorithmTag encAlgorithm, HashAlgorithmTag hashAlgorithm, byte[] rawPassPhrase, bool clearPassPhrase, SecureRandom random, out S2k s2k, out byte[] iv)
|
||||
{
|
||||
s2k = PgpUtilities.GenerateS2k(hashAlgorithm, 96, random);
|
||||
KeyParameter key = PgpUtilities.DoMakeKeyFromPassPhrase(encAlgorithm, s2k, rawPassPhrase, clearPassPhrase);
|
||||
iv = null;
|
||||
return EncryptData(encAlgorithm, key, rawKeyData, 0, rawKeyData.Length, random, ref iv);
|
||||
}
|
||||
|
||||
private static byte[] EncryptData(SymmetricKeyAlgorithmTag encAlgorithm, KeyParameter key, byte[] data, int dataOff, int dataLen, SecureRandom random, ref byte[] iv)
|
||||
{
|
||||
IBufferedCipher cipher;
|
||||
try
|
||||
{
|
||||
string symmetricCipherName = PgpUtilities.GetSymmetricCipherName(encAlgorithm);
|
||||
cipher = CipherUtilities.GetCipher(symmetricCipherName + "/CFB/NoPadding");
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw new PgpException("Exception creating cipher", exception);
|
||||
}
|
||||
if (iv == null)
|
||||
{
|
||||
iv = PgpUtilities.GenerateIV(cipher.GetBlockSize(), random);
|
||||
}
|
||||
cipher.Init(forEncryption: true, new ParametersWithRandom(new ParametersWithIV(key, iv), random));
|
||||
return cipher.DoFinal(data, dataOff, dataLen);
|
||||
}
|
||||
|
||||
public static PgpSecretKey ParseSecretKeyFromSExpr(Stream inputStream, char[] passPhrase, PgpPublicKey pubKey)
|
||||
{
|
||||
return DoParseSecretKeyFromSExpr(inputStream, PgpUtilities.EncodePassPhrase(passPhrase, utf8: false), clearPassPhrase: true, pubKey);
|
||||
}
|
||||
|
||||
public static PgpSecretKey ParseSecretKeyFromSExprUtf8(Stream inputStream, char[] passPhrase, PgpPublicKey pubKey)
|
||||
{
|
||||
return DoParseSecretKeyFromSExpr(inputStream, PgpUtilities.EncodePassPhrase(passPhrase, utf8: true), clearPassPhrase: true, pubKey);
|
||||
}
|
||||
|
||||
public static PgpSecretKey ParseSecretKeyFromSExprRaw(Stream inputStream, byte[] rawPassPhrase, PgpPublicKey pubKey)
|
||||
{
|
||||
return DoParseSecretKeyFromSExpr(inputStream, rawPassPhrase, clearPassPhrase: false, pubKey);
|
||||
}
|
||||
|
||||
internal static PgpSecretKey DoParseSecretKeyFromSExpr(Stream inputStream, byte[] rawPassPhrase, bool clearPassPhrase, PgpPublicKey pubKey)
|
||||
{
|
||||
SXprUtilities.SkipOpenParenthesis(inputStream);
|
||||
string text = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
|
||||
if (text.Equals("protected-private-key"))
|
||||
{
|
||||
SXprUtilities.SkipOpenParenthesis(inputStream);
|
||||
string text2 = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
|
||||
if (text2.Equals("ecc"))
|
||||
{
|
||||
SXprUtilities.SkipOpenParenthesis(inputStream);
|
||||
SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
|
||||
string curveName = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
|
||||
SXprUtilities.SkipCloseParenthesis(inputStream);
|
||||
SXprUtilities.SkipOpenParenthesis(inputStream);
|
||||
text = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
|
||||
if (text.Equals("q"))
|
||||
{
|
||||
SXprUtilities.ReadBytes(inputStream, inputStream.ReadByte());
|
||||
SXprUtilities.SkipCloseParenthesis(inputStream);
|
||||
byte[] dValue = GetDValue(inputStream, rawPassPhrase, clearPassPhrase, curveName);
|
||||
return new PgpSecretKey(new SecretKeyPacket(pubKey.PublicKeyPacket, SymmetricKeyAlgorithmTag.Null, null, null, new ECSecretBcpgKey(new BigInteger(1, dValue)).GetEncoded()), pubKey);
|
||||
}
|
||||
throw new PgpException("no q value found");
|
||||
}
|
||||
throw new PgpException("no curve details found");
|
||||
}
|
||||
throw new PgpException("unknown key type found");
|
||||
}
|
||||
|
||||
public static PgpSecretKey ParseSecretKeyFromSExpr(Stream inputStream, char[] passPhrase)
|
||||
{
|
||||
return DoParseSecretKeyFromSExpr(inputStream, PgpUtilities.EncodePassPhrase(passPhrase, utf8: false), clearPassPhrase: true);
|
||||
}
|
||||
|
||||
public static PgpSecretKey ParseSecretKeyFromSExprUtf8(Stream inputStream, char[] passPhrase)
|
||||
{
|
||||
return DoParseSecretKeyFromSExpr(inputStream, PgpUtilities.EncodePassPhrase(passPhrase, utf8: true), clearPassPhrase: true);
|
||||
}
|
||||
|
||||
public static PgpSecretKey ParseSecretKeyFromSExprRaw(Stream inputStream, byte[] rawPassPhrase)
|
||||
{
|
||||
return DoParseSecretKeyFromSExpr(inputStream, rawPassPhrase, clearPassPhrase: false);
|
||||
}
|
||||
|
||||
internal static PgpSecretKey DoParseSecretKeyFromSExpr(Stream inputStream, byte[] rawPassPhrase, bool clearPassPhrase)
|
||||
{
|
||||
SXprUtilities.SkipOpenParenthesis(inputStream);
|
||||
string text = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
|
||||
if (text.Equals("protected-private-key"))
|
||||
{
|
||||
SXprUtilities.SkipOpenParenthesis(inputStream);
|
||||
string text2 = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
|
||||
if (text2.Equals("ecc"))
|
||||
{
|
||||
SXprUtilities.SkipOpenParenthesis(inputStream);
|
||||
SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
|
||||
string text3 = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
|
||||
if (Platform.StartsWith(text3, "NIST "))
|
||||
{
|
||||
text3 = text3.Substring("NIST ".Length);
|
||||
}
|
||||
SXprUtilities.SkipCloseParenthesis(inputStream);
|
||||
SXprUtilities.SkipOpenParenthesis(inputStream);
|
||||
text = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
|
||||
if (text.Equals("q"))
|
||||
{
|
||||
byte[] bytes = SXprUtilities.ReadBytes(inputStream, inputStream.ReadByte());
|
||||
PublicKeyPacket publicKeyPacket = new PublicKeyPacket(PublicKeyAlgorithmTag.ECDsa, DateTime.UtcNow, new ECDsaPublicBcpgKey(ECNamedCurveTable.GetOid(text3), new BigInteger(1, bytes)));
|
||||
SXprUtilities.SkipCloseParenthesis(inputStream);
|
||||
byte[] dValue = GetDValue(inputStream, rawPassPhrase, clearPassPhrase, text3);
|
||||
return new PgpSecretKey(new SecretKeyPacket(publicKeyPacket, SymmetricKeyAlgorithmTag.Null, null, null, new ECSecretBcpgKey(new BigInteger(1, dValue)).GetEncoded()), new PgpPublicKey(publicKeyPacket));
|
||||
}
|
||||
throw new PgpException("no q value found");
|
||||
}
|
||||
throw new PgpException("no curve details found");
|
||||
}
|
||||
throw new PgpException("unknown key type found");
|
||||
}
|
||||
|
||||
private static byte[] GetDValue(Stream inputStream, byte[] rawPassPhrase, bool clearPassPhrase, string curveName)
|
||||
{
|
||||
SXprUtilities.SkipOpenParenthesis(inputStream);
|
||||
string text = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
|
||||
if (text.Equals("protected"))
|
||||
{
|
||||
SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
|
||||
SXprUtilities.SkipOpenParenthesis(inputStream);
|
||||
S2k s2k = SXprUtilities.ParseS2k(inputStream);
|
||||
byte[] iv = SXprUtilities.ReadBytes(inputStream, inputStream.ReadByte());
|
||||
SXprUtilities.SkipCloseParenthesis(inputStream);
|
||||
byte[] array = SXprUtilities.ReadBytes(inputStream, inputStream.ReadByte());
|
||||
KeyParameter key = PgpUtilities.DoMakeKeyFromPassPhrase(SymmetricKeyAlgorithmTag.Aes128, s2k, rawPassPhrase, clearPassPhrase);
|
||||
byte[] buffer = RecoverKeyData(SymmetricKeyAlgorithmTag.Aes128, "/CBC/NoPadding", key, iv, array, 0, array.Length);
|
||||
Stream stream = new MemoryStream(buffer, writable: false);
|
||||
SXprUtilities.SkipOpenParenthesis(stream);
|
||||
SXprUtilities.SkipOpenParenthesis(stream);
|
||||
SXprUtilities.SkipOpenParenthesis(stream);
|
||||
SXprUtilities.ReadString(stream, stream.ReadByte());
|
||||
return SXprUtilities.ReadBytes(stream, stream.ReadByte());
|
||||
}
|
||||
throw new PgpException("protected block not found");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
using Org.BouncyCastle.Utilities.Collections;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpSecretKeyRing : PgpKeyRing
|
||||
{
|
||||
private readonly IList keys;
|
||||
|
||||
private readonly IList extraPubKeys;
|
||||
|
||||
internal PgpSecretKeyRing(IList keys)
|
||||
: this(keys, Platform.CreateArrayList())
|
||||
{
|
||||
}
|
||||
|
||||
private PgpSecretKeyRing(IList keys, IList extraPubKeys)
|
||||
{
|
||||
this.keys = keys;
|
||||
this.extraPubKeys = extraPubKeys;
|
||||
}
|
||||
|
||||
public PgpSecretKeyRing(byte[] encoding)
|
||||
: this(new MemoryStream(encoding))
|
||||
{
|
||||
}
|
||||
|
||||
public PgpSecretKeyRing(Stream inputStream)
|
||||
{
|
||||
keys = Platform.CreateArrayList();
|
||||
extraPubKeys = Platform.CreateArrayList();
|
||||
BcpgInputStream bcpgInputStream = BcpgInputStream.Wrap(inputStream);
|
||||
PacketTag packetTag = bcpgInputStream.NextPacketTag();
|
||||
if (packetTag != PacketTag.SecretKey && packetTag != PacketTag.SecretSubkey)
|
||||
{
|
||||
int num = (int)packetTag;
|
||||
throw new IOException("secret key ring doesn't start with secret key tag: tag 0x" + num.ToString("X"));
|
||||
}
|
||||
SecretKeyPacket secretKeyPacket = (SecretKeyPacket)bcpgInputStream.ReadPacket();
|
||||
while (bcpgInputStream.NextPacketTag() == PacketTag.Experimental2)
|
||||
{
|
||||
bcpgInputStream.ReadPacket();
|
||||
}
|
||||
TrustPacket trustPk = PgpKeyRing.ReadOptionalTrustPacket(bcpgInputStream);
|
||||
IList keySigs = PgpKeyRing.ReadSignaturesAndTrust(bcpgInputStream);
|
||||
PgpKeyRing.ReadUserIDs(bcpgInputStream, out var ids, out var idTrusts, out var idSigs);
|
||||
keys.Add(new PgpSecretKey(secretKeyPacket, new PgpPublicKey(secretKeyPacket.PublicKeyPacket, trustPk, keySigs, ids, idTrusts, idSigs)));
|
||||
while (bcpgInputStream.NextPacketTag() == PacketTag.SecretSubkey || bcpgInputStream.NextPacketTag() == PacketTag.PublicSubkey)
|
||||
{
|
||||
if (bcpgInputStream.NextPacketTag() == PacketTag.SecretSubkey)
|
||||
{
|
||||
SecretSubkeyPacket secretSubkeyPacket = (SecretSubkeyPacket)bcpgInputStream.ReadPacket();
|
||||
while (bcpgInputStream.NextPacketTag() == PacketTag.Experimental2)
|
||||
{
|
||||
bcpgInputStream.ReadPacket();
|
||||
}
|
||||
TrustPacket trustPk2 = PgpKeyRing.ReadOptionalTrustPacket(bcpgInputStream);
|
||||
IList sigs = PgpKeyRing.ReadSignaturesAndTrust(bcpgInputStream);
|
||||
keys.Add(new PgpSecretKey(secretSubkeyPacket, new PgpPublicKey(secretSubkeyPacket.PublicKeyPacket, trustPk2, sigs)));
|
||||
}
|
||||
else
|
||||
{
|
||||
PublicSubkeyPacket publicPk = (PublicSubkeyPacket)bcpgInputStream.ReadPacket();
|
||||
TrustPacket trustPk3 = PgpKeyRing.ReadOptionalTrustPacket(bcpgInputStream);
|
||||
IList sigs2 = PgpKeyRing.ReadSignaturesAndTrust(bcpgInputStream);
|
||||
extraPubKeys.Add(new PgpPublicKey(publicPk, trustPk3, sigs2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public PgpPublicKey GetPublicKey()
|
||||
{
|
||||
return ((PgpSecretKey)keys[0]).PublicKey;
|
||||
}
|
||||
|
||||
public PgpSecretKey GetSecretKey()
|
||||
{
|
||||
return (PgpSecretKey)keys[0];
|
||||
}
|
||||
|
||||
public IEnumerable GetSecretKeys()
|
||||
{
|
||||
return new EnumerableProxy(keys);
|
||||
}
|
||||
|
||||
public PgpSecretKey GetSecretKey(long keyId)
|
||||
{
|
||||
foreach (PgpSecretKey key in keys)
|
||||
{
|
||||
if (keyId == key.KeyId)
|
||||
{
|
||||
return key;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public IEnumerable GetExtraPublicKeys()
|
||||
{
|
||||
return new EnumerableProxy(extraPubKeys);
|
||||
}
|
||||
|
||||
public byte[] GetEncoded()
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
Encode(memoryStream);
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
|
||||
public void Encode(Stream outStr)
|
||||
{
|
||||
if (outStr == null)
|
||||
{
|
||||
throw new ArgumentNullException("outStr");
|
||||
}
|
||||
foreach (PgpSecretKey key in keys)
|
||||
{
|
||||
key.Encode(outStr);
|
||||
}
|
||||
foreach (PgpPublicKey extraPubKey in extraPubKeys)
|
||||
{
|
||||
extraPubKey.Encode(outStr);
|
||||
}
|
||||
}
|
||||
|
||||
public static PgpSecretKeyRing ReplacePublicKeys(PgpSecretKeyRing secretRing, PgpPublicKeyRing publicRing)
|
||||
{
|
||||
IList list = Platform.CreateArrayList(secretRing.keys.Count);
|
||||
foreach (PgpSecretKey key in secretRing.keys)
|
||||
{
|
||||
PgpPublicKey publicKey = publicRing.GetPublicKey(key.KeyId);
|
||||
list.Add(PgpSecretKey.ReplacePublicKey(key, publicKey));
|
||||
}
|
||||
return new PgpSecretKeyRing(list);
|
||||
}
|
||||
|
||||
public static PgpSecretKeyRing CopyWithNewPassword(PgpSecretKeyRing ring, char[] oldPassPhrase, char[] newPassPhrase, SymmetricKeyAlgorithmTag newEncAlgorithm, SecureRandom rand)
|
||||
{
|
||||
IList list = Platform.CreateArrayList(ring.keys.Count);
|
||||
foreach (PgpSecretKey secretKey in ring.GetSecretKeys())
|
||||
{
|
||||
if (secretKey.IsPrivateKeyEmpty)
|
||||
{
|
||||
list.Add(secretKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
list.Add(PgpSecretKey.CopyWithNewPassword(secretKey, oldPassPhrase, newPassPhrase, newEncAlgorithm, rand));
|
||||
}
|
||||
}
|
||||
return new PgpSecretKeyRing(list, ring.extraPubKeys);
|
||||
}
|
||||
|
||||
public static PgpSecretKeyRing InsertSecretKey(PgpSecretKeyRing secRing, PgpSecretKey secKey)
|
||||
{
|
||||
IList list = Platform.CreateArrayList(secRing.keys);
|
||||
bool flag = false;
|
||||
bool flag2 = false;
|
||||
for (int i = 0; i != list.Count; i++)
|
||||
{
|
||||
PgpSecretKey pgpSecretKey = (PgpSecretKey)list[i];
|
||||
if (pgpSecretKey.KeyId == secKey.KeyId)
|
||||
{
|
||||
flag = true;
|
||||
list[i] = secKey;
|
||||
}
|
||||
if (pgpSecretKey.IsMasterKey)
|
||||
{
|
||||
flag2 = true;
|
||||
}
|
||||
}
|
||||
if (!flag)
|
||||
{
|
||||
if (secKey.IsMasterKey)
|
||||
{
|
||||
if (flag2)
|
||||
{
|
||||
throw new ArgumentException("cannot add a master key to a ring that already has one");
|
||||
}
|
||||
list.Insert(0, secKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
list.Add(secKey);
|
||||
}
|
||||
}
|
||||
return new PgpSecretKeyRing(list, secRing.extraPubKeys);
|
||||
}
|
||||
|
||||
public static PgpSecretKeyRing RemoveSecretKey(PgpSecretKeyRing secRing, PgpSecretKey secKey)
|
||||
{
|
||||
IList list = Platform.CreateArrayList(secRing.keys);
|
||||
bool flag = false;
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
PgpSecretKey pgpSecretKey = (PgpSecretKey)list[i];
|
||||
if (pgpSecretKey.KeyId == secKey.KeyId)
|
||||
{
|
||||
flag = true;
|
||||
list.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
if (!flag)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return new PgpSecretKeyRing(list, secRing.extraPubKeys);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
using Org.BouncyCastle.Utilities.Collections;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpSecretKeyRingBundle
|
||||
{
|
||||
private readonly IDictionary secretRings;
|
||||
|
||||
private readonly IList order;
|
||||
|
||||
[Obsolete("Use 'Count' property instead")]
|
||||
public int Size => order.Count;
|
||||
|
||||
public int Count => order.Count;
|
||||
|
||||
private PgpSecretKeyRingBundle(IDictionary secretRings, IList order)
|
||||
{
|
||||
this.secretRings = secretRings;
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
public PgpSecretKeyRingBundle(byte[] encoding)
|
||||
: this(new MemoryStream(encoding, writable: false))
|
||||
{
|
||||
}
|
||||
|
||||
public PgpSecretKeyRingBundle(Stream inputStream)
|
||||
: this(new PgpObjectFactory(inputStream).AllPgpObjects())
|
||||
{
|
||||
}
|
||||
|
||||
public PgpSecretKeyRingBundle(IEnumerable e)
|
||||
{
|
||||
secretRings = Platform.CreateHashtable();
|
||||
order = Platform.CreateArrayList();
|
||||
foreach (object item in e)
|
||||
{
|
||||
if (!(item is PgpSecretKeyRing pgpSecretKeyRing))
|
||||
{
|
||||
throw new PgpException(Platform.GetTypeName(item) + " found where PgpSecretKeyRing expected");
|
||||
}
|
||||
long keyId = pgpSecretKeyRing.GetPublicKey().KeyId;
|
||||
secretRings.Add(keyId, pgpSecretKeyRing);
|
||||
order.Add(keyId);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable GetKeyRings()
|
||||
{
|
||||
return new EnumerableProxy(secretRings.Values);
|
||||
}
|
||||
|
||||
public IEnumerable GetKeyRings(string userId)
|
||||
{
|
||||
return GetKeyRings(userId, matchPartial: false, ignoreCase: false);
|
||||
}
|
||||
|
||||
public IEnumerable GetKeyRings(string userId, bool matchPartial)
|
||||
{
|
||||
return GetKeyRings(userId, matchPartial, ignoreCase: false);
|
||||
}
|
||||
|
||||
public IEnumerable GetKeyRings(string userId, bool matchPartial, bool ignoreCase)
|
||||
{
|
||||
IList list = Platform.CreateArrayList();
|
||||
if (ignoreCase)
|
||||
{
|
||||
userId = Platform.ToUpperInvariant(userId);
|
||||
}
|
||||
foreach (PgpSecretKeyRing keyRing in GetKeyRings())
|
||||
{
|
||||
foreach (string userId2 in keyRing.GetSecretKey().UserIds)
|
||||
{
|
||||
string text2 = userId2;
|
||||
if (ignoreCase)
|
||||
{
|
||||
text2 = Platform.ToUpperInvariant(text2);
|
||||
}
|
||||
if (matchPartial)
|
||||
{
|
||||
if (Platform.IndexOf(text2, userId) > -1)
|
||||
{
|
||||
list.Add(keyRing);
|
||||
}
|
||||
}
|
||||
else if (text2.Equals(userId))
|
||||
{
|
||||
list.Add(keyRing);
|
||||
}
|
||||
}
|
||||
}
|
||||
return new EnumerableProxy(list);
|
||||
}
|
||||
|
||||
public PgpSecretKey GetSecretKey(long keyId)
|
||||
{
|
||||
foreach (PgpSecretKeyRing keyRing in GetKeyRings())
|
||||
{
|
||||
PgpSecretKey secretKey = keyRing.GetSecretKey(keyId);
|
||||
if (secretKey != null)
|
||||
{
|
||||
return secretKey;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public PgpSecretKeyRing GetSecretKeyRing(long keyId)
|
||||
{
|
||||
if (secretRings.Contains(keyId))
|
||||
{
|
||||
return (PgpSecretKeyRing)secretRings[keyId];
|
||||
}
|
||||
foreach (PgpSecretKeyRing keyRing in GetKeyRings())
|
||||
{
|
||||
PgpSecretKey secretKey = keyRing.GetSecretKey(keyId);
|
||||
if (secretKey != null)
|
||||
{
|
||||
return keyRing;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool Contains(long keyID)
|
||||
{
|
||||
return GetSecretKey(keyID) != null;
|
||||
}
|
||||
|
||||
public byte[] GetEncoded()
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
Encode(memoryStream);
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
|
||||
public void Encode(Stream outStr)
|
||||
{
|
||||
BcpgOutputStream outStr2 = BcpgOutputStream.Wrap(outStr);
|
||||
foreach (object item in order)
|
||||
{
|
||||
long num = (long)item;
|
||||
PgpSecretKeyRing pgpSecretKeyRing = (PgpSecretKeyRing)secretRings[num];
|
||||
pgpSecretKeyRing.Encode(outStr2);
|
||||
}
|
||||
}
|
||||
|
||||
public static PgpSecretKeyRingBundle AddSecretKeyRing(PgpSecretKeyRingBundle bundle, PgpSecretKeyRing secretKeyRing)
|
||||
{
|
||||
long keyId = secretKeyRing.GetPublicKey().KeyId;
|
||||
if (bundle.secretRings.Contains(keyId))
|
||||
{
|
||||
throw new ArgumentException("Collection already contains a key with a keyId for the passed in ring.");
|
||||
}
|
||||
IDictionary dictionary = Platform.CreateHashtable(bundle.secretRings);
|
||||
IList list = Platform.CreateArrayList(bundle.order);
|
||||
dictionary[keyId] = secretKeyRing;
|
||||
list.Add(keyId);
|
||||
return new PgpSecretKeyRingBundle(dictionary, list);
|
||||
}
|
||||
|
||||
public static PgpSecretKeyRingBundle RemoveSecretKeyRing(PgpSecretKeyRingBundle bundle, PgpSecretKeyRing secretKeyRing)
|
||||
{
|
||||
long keyId = secretKeyRing.GetPublicKey().KeyId;
|
||||
if (!bundle.secretRings.Contains(keyId))
|
||||
{
|
||||
throw new ArgumentException("Collection does not contain a key with a keyId for the passed in ring.");
|
||||
}
|
||||
IDictionary dictionary = Platform.CreateHashtable(bundle.secretRings);
|
||||
IList list = Platform.CreateArrayList(bundle.order);
|
||||
dictionary.Remove(keyId);
|
||||
list.Remove(keyId);
|
||||
return new PgpSecretKeyRingBundle(dictionary, list);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,343 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Asn1;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
using Org.BouncyCastle.Utilities.Date;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpSignature
|
||||
{
|
||||
public const int BinaryDocument = 0;
|
||||
|
||||
public const int CanonicalTextDocument = 1;
|
||||
|
||||
public const int StandAlone = 2;
|
||||
|
||||
public const int DefaultCertification = 16;
|
||||
|
||||
public const int NoCertification = 17;
|
||||
|
||||
public const int CasualCertification = 18;
|
||||
|
||||
public const int PositiveCertification = 19;
|
||||
|
||||
public const int SubkeyBinding = 24;
|
||||
|
||||
public const int PrimaryKeyBinding = 25;
|
||||
|
||||
public const int DirectKey = 31;
|
||||
|
||||
public const int KeyRevocation = 32;
|
||||
|
||||
public const int SubkeyRevocation = 40;
|
||||
|
||||
public const int CertificationRevocation = 48;
|
||||
|
||||
public const int Timestamp = 64;
|
||||
|
||||
private readonly SignaturePacket sigPck;
|
||||
|
||||
private readonly int signatureType;
|
||||
|
||||
private readonly TrustPacket trustPck;
|
||||
|
||||
private ISigner sig;
|
||||
|
||||
private byte lastb;
|
||||
|
||||
public int Version => sigPck.Version;
|
||||
|
||||
public PublicKeyAlgorithmTag KeyAlgorithm => sigPck.KeyAlgorithm;
|
||||
|
||||
public HashAlgorithmTag HashAlgorithm => sigPck.HashAlgorithm;
|
||||
|
||||
public int SignatureType => sigPck.SignatureType;
|
||||
|
||||
public long KeyId => sigPck.KeyId;
|
||||
|
||||
public DateTime CreationTime => DateTimeUtilities.UnixMsToDateTime(sigPck.CreationTime);
|
||||
|
||||
public bool HasSubpackets
|
||||
{
|
||||
get
|
||||
{
|
||||
if (sigPck.GetHashedSubPackets() == null)
|
||||
{
|
||||
return sigPck.GetUnhashedSubPackets() != null;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
internal PgpSignature(BcpgInputStream bcpgInput)
|
||||
: this((SignaturePacket)bcpgInput.ReadPacket())
|
||||
{
|
||||
}
|
||||
|
||||
internal PgpSignature(SignaturePacket sigPacket)
|
||||
: this(sigPacket, null)
|
||||
{
|
||||
}
|
||||
|
||||
internal PgpSignature(SignaturePacket sigPacket, TrustPacket trustPacket)
|
||||
{
|
||||
if (sigPacket == null)
|
||||
{
|
||||
throw new ArgumentNullException("sigPacket");
|
||||
}
|
||||
sigPck = sigPacket;
|
||||
signatureType = sigPck.SignatureType;
|
||||
trustPck = trustPacket;
|
||||
}
|
||||
|
||||
private void GetSig()
|
||||
{
|
||||
sig = SignerUtilities.GetSigner(PgpUtilities.GetSignatureName(sigPck.KeyAlgorithm, sigPck.HashAlgorithm));
|
||||
}
|
||||
|
||||
public bool IsCertification()
|
||||
{
|
||||
return IsCertification(SignatureType);
|
||||
}
|
||||
|
||||
public void InitVerify(PgpPublicKey pubKey)
|
||||
{
|
||||
lastb = 0;
|
||||
if (sig == null)
|
||||
{
|
||||
GetSig();
|
||||
}
|
||||
try
|
||||
{
|
||||
sig.Init(forSigning: false, pubKey.GetKey());
|
||||
}
|
||||
catch (InvalidKeyException exception)
|
||||
{
|
||||
throw new PgpException("invalid key.", exception);
|
||||
}
|
||||
}
|
||||
|
||||
public void Update(byte b)
|
||||
{
|
||||
if (signatureType == 1)
|
||||
{
|
||||
doCanonicalUpdateByte(b);
|
||||
}
|
||||
else
|
||||
{
|
||||
sig.Update(b);
|
||||
}
|
||||
}
|
||||
|
||||
private void doCanonicalUpdateByte(byte b)
|
||||
{
|
||||
switch (b)
|
||||
{
|
||||
case 13:
|
||||
doUpdateCRLF();
|
||||
break;
|
||||
case 10:
|
||||
if (lastb != 13)
|
||||
{
|
||||
doUpdateCRLF();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
sig.Update(b);
|
||||
break;
|
||||
}
|
||||
lastb = b;
|
||||
}
|
||||
|
||||
private void doUpdateCRLF()
|
||||
{
|
||||
sig.Update(13);
|
||||
sig.Update(10);
|
||||
}
|
||||
|
||||
public void Update(params byte[] bytes)
|
||||
{
|
||||
Update(bytes, 0, bytes.Length);
|
||||
}
|
||||
|
||||
public void Update(byte[] bytes, int off, int length)
|
||||
{
|
||||
if (signatureType == 1)
|
||||
{
|
||||
int num = off + length;
|
||||
for (int i = off; i != num; i++)
|
||||
{
|
||||
doCanonicalUpdateByte(bytes[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sig.BlockUpdate(bytes, off, length);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Verify()
|
||||
{
|
||||
byte[] signatureTrailer = GetSignatureTrailer();
|
||||
sig.BlockUpdate(signatureTrailer, 0, signatureTrailer.Length);
|
||||
return sig.VerifySignature(GetSignature());
|
||||
}
|
||||
|
||||
private void UpdateWithIdData(int header, byte[] idBytes)
|
||||
{
|
||||
Update((byte)header, (byte)(idBytes.Length >> 24), (byte)(idBytes.Length >> 16), (byte)(idBytes.Length >> 8), (byte)idBytes.Length);
|
||||
Update(idBytes);
|
||||
}
|
||||
|
||||
private void UpdateWithPublicKey(PgpPublicKey key)
|
||||
{
|
||||
byte[] encodedPublicKey = GetEncodedPublicKey(key);
|
||||
Update(153, (byte)(encodedPublicKey.Length >> 8), (byte)encodedPublicKey.Length);
|
||||
Update(encodedPublicKey);
|
||||
}
|
||||
|
||||
public bool VerifyCertification(PgpUserAttributeSubpacketVector userAttributes, PgpPublicKey key)
|
||||
{
|
||||
UpdateWithPublicKey(key);
|
||||
try
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
UserAttributeSubpacket[] array = userAttributes.ToSubpacketArray();
|
||||
foreach (UserAttributeSubpacket userAttributeSubpacket in array)
|
||||
{
|
||||
userAttributeSubpacket.Encode(memoryStream);
|
||||
}
|
||||
UpdateWithIdData(209, memoryStream.ToArray());
|
||||
}
|
||||
catch (IOException exception)
|
||||
{
|
||||
throw new PgpException("cannot encode subpacket array", exception);
|
||||
}
|
||||
Update(sigPck.GetSignatureTrailer());
|
||||
return sig.VerifySignature(GetSignature());
|
||||
}
|
||||
|
||||
public bool VerifyCertification(string id, PgpPublicKey key)
|
||||
{
|
||||
UpdateWithPublicKey(key);
|
||||
UpdateWithIdData(180, Strings.ToUtf8ByteArray(id));
|
||||
Update(sigPck.GetSignatureTrailer());
|
||||
return sig.VerifySignature(GetSignature());
|
||||
}
|
||||
|
||||
public bool VerifyCertification(PgpPublicKey masterKey, PgpPublicKey pubKey)
|
||||
{
|
||||
UpdateWithPublicKey(masterKey);
|
||||
UpdateWithPublicKey(pubKey);
|
||||
Update(sigPck.GetSignatureTrailer());
|
||||
return sig.VerifySignature(GetSignature());
|
||||
}
|
||||
|
||||
public bool VerifyCertification(PgpPublicKey pubKey)
|
||||
{
|
||||
if (SignatureType != 32 && SignatureType != 40)
|
||||
{
|
||||
throw new InvalidOperationException("signature is not a key signature");
|
||||
}
|
||||
UpdateWithPublicKey(pubKey);
|
||||
Update(sigPck.GetSignatureTrailer());
|
||||
return sig.VerifySignature(GetSignature());
|
||||
}
|
||||
|
||||
[Obsolete("Use 'CreationTime' property instead")]
|
||||
public DateTime GetCreationTime()
|
||||
{
|
||||
return CreationTime;
|
||||
}
|
||||
|
||||
public byte[] GetSignatureTrailer()
|
||||
{
|
||||
return sigPck.GetSignatureTrailer();
|
||||
}
|
||||
|
||||
public PgpSignatureSubpacketVector GetHashedSubPackets()
|
||||
{
|
||||
return createSubpacketVector(sigPck.GetHashedSubPackets());
|
||||
}
|
||||
|
||||
public PgpSignatureSubpacketVector GetUnhashedSubPackets()
|
||||
{
|
||||
return createSubpacketVector(sigPck.GetUnhashedSubPackets());
|
||||
}
|
||||
|
||||
private PgpSignatureSubpacketVector createSubpacketVector(SignatureSubpacket[] pcks)
|
||||
{
|
||||
if (pcks != null)
|
||||
{
|
||||
return new PgpSignatureSubpacketVector(pcks);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public byte[] GetSignature()
|
||||
{
|
||||
MPInteger[] signature = sigPck.GetSignature();
|
||||
if (signature != null)
|
||||
{
|
||||
if (signature.Length == 1)
|
||||
{
|
||||
return signature[0].Value.ToByteArrayUnsigned();
|
||||
}
|
||||
try
|
||||
{
|
||||
return new DerSequence(new DerInteger(signature[0].Value), new DerInteger(signature[1].Value)).GetEncoded();
|
||||
}
|
||||
catch (IOException exception)
|
||||
{
|
||||
throw new PgpException("exception encoding DSA sig.", exception);
|
||||
}
|
||||
}
|
||||
return sigPck.GetSignatureBytes();
|
||||
}
|
||||
|
||||
public byte[] GetEncoded()
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
Encode(memoryStream);
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
|
||||
public void Encode(Stream outStream)
|
||||
{
|
||||
BcpgOutputStream bcpgOutputStream = BcpgOutputStream.Wrap(outStream);
|
||||
bcpgOutputStream.WritePacket(sigPck);
|
||||
if (trustPck != null)
|
||||
{
|
||||
bcpgOutputStream.WritePacket(trustPck);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] GetEncodedPublicKey(PgpPublicKey pubKey)
|
||||
{
|
||||
try
|
||||
{
|
||||
return pubKey.publicPk.GetEncodedContents();
|
||||
}
|
||||
catch (IOException exception)
|
||||
{
|
||||
throw new PgpException("exception preparing key.", exception);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsCertification(int signatureType)
|
||||
{
|
||||
switch (signatureType)
|
||||
{
|
||||
case 16:
|
||||
case 17:
|
||||
case 18:
|
||||
case 19:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,292 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Bcpg.Sig;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpSignatureGenerator
|
||||
{
|
||||
private static readonly SignatureSubpacket[] EmptySignatureSubpackets = new SignatureSubpacket[0];
|
||||
|
||||
private PublicKeyAlgorithmTag keyAlgorithm;
|
||||
|
||||
private HashAlgorithmTag hashAlgorithm;
|
||||
|
||||
private PgpPrivateKey privKey;
|
||||
|
||||
private ISigner sig;
|
||||
|
||||
private IDigest dig;
|
||||
|
||||
private int signatureType;
|
||||
|
||||
private byte lastb;
|
||||
|
||||
private SignatureSubpacket[] unhashed = EmptySignatureSubpackets;
|
||||
|
||||
private SignatureSubpacket[] hashed = EmptySignatureSubpackets;
|
||||
|
||||
public PgpSignatureGenerator(PublicKeyAlgorithmTag keyAlgorithm, HashAlgorithmTag hashAlgorithm)
|
||||
{
|
||||
this.keyAlgorithm = keyAlgorithm;
|
||||
this.hashAlgorithm = hashAlgorithm;
|
||||
dig = DigestUtilities.GetDigest(PgpUtilities.GetDigestName(hashAlgorithm));
|
||||
sig = SignerUtilities.GetSigner(PgpUtilities.GetSignatureName(keyAlgorithm, hashAlgorithm));
|
||||
}
|
||||
|
||||
public void InitSign(int sigType, PgpPrivateKey key)
|
||||
{
|
||||
InitSign(sigType, key, null);
|
||||
}
|
||||
|
||||
public void InitSign(int sigType, PgpPrivateKey key, SecureRandom random)
|
||||
{
|
||||
privKey = key;
|
||||
signatureType = sigType;
|
||||
try
|
||||
{
|
||||
ICipherParameters parameters = key.Key;
|
||||
if (random != null)
|
||||
{
|
||||
parameters = new ParametersWithRandom(key.Key, random);
|
||||
}
|
||||
sig.Init(forSigning: true, parameters);
|
||||
}
|
||||
catch (InvalidKeyException exception)
|
||||
{
|
||||
throw new PgpException("invalid key.", exception);
|
||||
}
|
||||
dig.Reset();
|
||||
lastb = 0;
|
||||
}
|
||||
|
||||
public void Update(byte b)
|
||||
{
|
||||
if (signatureType == 1)
|
||||
{
|
||||
doCanonicalUpdateByte(b);
|
||||
}
|
||||
else
|
||||
{
|
||||
doUpdateByte(b);
|
||||
}
|
||||
}
|
||||
|
||||
private void doCanonicalUpdateByte(byte b)
|
||||
{
|
||||
switch (b)
|
||||
{
|
||||
case 13:
|
||||
doUpdateCRLF();
|
||||
break;
|
||||
case 10:
|
||||
if (lastb != 13)
|
||||
{
|
||||
doUpdateCRLF();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
doUpdateByte(b);
|
||||
break;
|
||||
}
|
||||
lastb = b;
|
||||
}
|
||||
|
||||
private void doUpdateCRLF()
|
||||
{
|
||||
doUpdateByte(13);
|
||||
doUpdateByte(10);
|
||||
}
|
||||
|
||||
private void doUpdateByte(byte b)
|
||||
{
|
||||
sig.Update(b);
|
||||
dig.Update(b);
|
||||
}
|
||||
|
||||
public void Update(params byte[] b)
|
||||
{
|
||||
Update(b, 0, b.Length);
|
||||
}
|
||||
|
||||
public void Update(byte[] b, int off, int len)
|
||||
{
|
||||
if (signatureType == 1)
|
||||
{
|
||||
int num = off + len;
|
||||
for (int i = off; i != num; i++)
|
||||
{
|
||||
doCanonicalUpdateByte(b[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sig.BlockUpdate(b, off, len);
|
||||
dig.BlockUpdate(b, off, len);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetHashedSubpackets(PgpSignatureSubpacketVector hashedPackets)
|
||||
{
|
||||
hashed = ((hashedPackets == null) ? EmptySignatureSubpackets : hashedPackets.ToSubpacketArray());
|
||||
}
|
||||
|
||||
public void SetUnhashedSubpackets(PgpSignatureSubpacketVector unhashedPackets)
|
||||
{
|
||||
unhashed = ((unhashedPackets == null) ? EmptySignatureSubpackets : unhashedPackets.ToSubpacketArray());
|
||||
}
|
||||
|
||||
public PgpOnePassSignature GenerateOnePassVersion(bool isNested)
|
||||
{
|
||||
return new PgpOnePassSignature(new OnePassSignaturePacket(signatureType, hashAlgorithm, keyAlgorithm, privKey.KeyId, isNested));
|
||||
}
|
||||
|
||||
public PgpSignature Generate()
|
||||
{
|
||||
SignatureSubpacket[] array = hashed;
|
||||
SignatureSubpacket[] array2 = unhashed;
|
||||
if (!packetPresent(hashed, SignatureSubpacketTag.CreationTime))
|
||||
{
|
||||
array = insertSubpacket(array, new SignatureCreationTime(critical: false, DateTime.UtcNow));
|
||||
}
|
||||
if (!packetPresent(hashed, SignatureSubpacketTag.IssuerKeyId) && !packetPresent(unhashed, SignatureSubpacketTag.IssuerKeyId))
|
||||
{
|
||||
array2 = insertSubpacket(array2, new IssuerKeyId(critical: false, privKey.KeyId));
|
||||
}
|
||||
int num = 4;
|
||||
byte[] array4;
|
||||
try
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
for (int i = 0; i != array.Length; i++)
|
||||
{
|
||||
array[i].Encode(memoryStream);
|
||||
}
|
||||
byte[] array3 = memoryStream.ToArray();
|
||||
MemoryStream memoryStream2 = new MemoryStream(array3.Length + 6);
|
||||
memoryStream2.WriteByte((byte)num);
|
||||
memoryStream2.WriteByte((byte)signatureType);
|
||||
memoryStream2.WriteByte((byte)keyAlgorithm);
|
||||
memoryStream2.WriteByte((byte)hashAlgorithm);
|
||||
memoryStream2.WriteByte((byte)(array3.Length >> 8));
|
||||
memoryStream2.WriteByte((byte)array3.Length);
|
||||
memoryStream2.Write(array3, 0, array3.Length);
|
||||
array4 = memoryStream2.ToArray();
|
||||
}
|
||||
catch (IOException exception)
|
||||
{
|
||||
throw new PgpException("exception encoding hashed data.", exception);
|
||||
}
|
||||
sig.BlockUpdate(array4, 0, array4.Length);
|
||||
dig.BlockUpdate(array4, 0, array4.Length);
|
||||
array4 = new byte[6]
|
||||
{
|
||||
(byte)num,
|
||||
255,
|
||||
(byte)(array4.Length >> 24),
|
||||
(byte)(array4.Length >> 16),
|
||||
(byte)(array4.Length >> 8),
|
||||
(byte)array4.Length
|
||||
};
|
||||
sig.BlockUpdate(array4, 0, array4.Length);
|
||||
dig.BlockUpdate(array4, 0, array4.Length);
|
||||
byte[] encoding = sig.GenerateSignature();
|
||||
byte[] array5 = DigestUtilities.DoFinal(dig);
|
||||
byte[] fingerprint = new byte[2]
|
||||
{
|
||||
array5[0],
|
||||
array5[1]
|
||||
};
|
||||
MPInteger[] signature = ((keyAlgorithm == PublicKeyAlgorithmTag.RsaSign || keyAlgorithm == PublicKeyAlgorithmTag.RsaGeneral) ? PgpUtilities.RsaSigToMpi(encoding) : PgpUtilities.DsaSigToMpi(encoding));
|
||||
return new PgpSignature(new SignaturePacket(signatureType, privKey.KeyId, keyAlgorithm, hashAlgorithm, array, array2, fingerprint, signature));
|
||||
}
|
||||
|
||||
public PgpSignature GenerateCertification(string id, PgpPublicKey pubKey)
|
||||
{
|
||||
UpdateWithPublicKey(pubKey);
|
||||
UpdateWithIdData(180, Strings.ToUtf8ByteArray(id));
|
||||
return Generate();
|
||||
}
|
||||
|
||||
public PgpSignature GenerateCertification(PgpUserAttributeSubpacketVector userAttributes, PgpPublicKey pubKey)
|
||||
{
|
||||
UpdateWithPublicKey(pubKey);
|
||||
try
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
UserAttributeSubpacket[] array = userAttributes.ToSubpacketArray();
|
||||
foreach (UserAttributeSubpacket userAttributeSubpacket in array)
|
||||
{
|
||||
userAttributeSubpacket.Encode(memoryStream);
|
||||
}
|
||||
UpdateWithIdData(209, memoryStream.ToArray());
|
||||
}
|
||||
catch (IOException exception)
|
||||
{
|
||||
throw new PgpException("cannot encode subpacket array", exception);
|
||||
}
|
||||
return Generate();
|
||||
}
|
||||
|
||||
public PgpSignature GenerateCertification(PgpPublicKey masterKey, PgpPublicKey pubKey)
|
||||
{
|
||||
UpdateWithPublicKey(masterKey);
|
||||
UpdateWithPublicKey(pubKey);
|
||||
return Generate();
|
||||
}
|
||||
|
||||
public PgpSignature GenerateCertification(PgpPublicKey pubKey)
|
||||
{
|
||||
UpdateWithPublicKey(pubKey);
|
||||
return Generate();
|
||||
}
|
||||
|
||||
private byte[] GetEncodedPublicKey(PgpPublicKey pubKey)
|
||||
{
|
||||
try
|
||||
{
|
||||
return pubKey.publicPk.GetEncodedContents();
|
||||
}
|
||||
catch (IOException exception)
|
||||
{
|
||||
throw new PgpException("exception preparing key.", exception);
|
||||
}
|
||||
}
|
||||
|
||||
private bool packetPresent(SignatureSubpacket[] packets, SignatureSubpacketTag type)
|
||||
{
|
||||
for (int i = 0; i != packets.Length; i++)
|
||||
{
|
||||
if (packets[i].SubpacketType == type)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private SignatureSubpacket[] insertSubpacket(SignatureSubpacket[] packets, SignatureSubpacket subpacket)
|
||||
{
|
||||
SignatureSubpacket[] array = new SignatureSubpacket[packets.Length + 1];
|
||||
array[0] = subpacket;
|
||||
packets.CopyTo(array, 1);
|
||||
return array;
|
||||
}
|
||||
|
||||
private void UpdateWithIdData(int header, byte[] idBytes)
|
||||
{
|
||||
Update((byte)header, (byte)(idBytes.Length >> 24), (byte)(idBytes.Length >> 16), (byte)(idBytes.Length >> 8), (byte)idBytes.Length);
|
||||
Update(idBytes);
|
||||
}
|
||||
|
||||
private void UpdateWithPublicKey(PgpPublicKey key)
|
||||
{
|
||||
byte[] encodedPublicKey = GetEncodedPublicKey(key);
|
||||
Update(153, (byte)(encodedPublicKey.Length >> 8), (byte)encodedPublicKey.Length);
|
||||
Update(encodedPublicKey);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpSignatureList : PgpObject
|
||||
{
|
||||
private PgpSignature[] sigs;
|
||||
|
||||
public PgpSignature this[int index] => sigs[index];
|
||||
|
||||
[Obsolete("Use 'Count' property instead")]
|
||||
public int Size => sigs.Length;
|
||||
|
||||
public int Count => sigs.Length;
|
||||
|
||||
public bool IsEmpty => sigs.Length == 0;
|
||||
|
||||
public PgpSignatureList(PgpSignature[] sigs)
|
||||
{
|
||||
this.sigs = (PgpSignature[])sigs.Clone();
|
||||
}
|
||||
|
||||
public PgpSignatureList(PgpSignature sig)
|
||||
{
|
||||
sigs = new PgpSignature[1] { sig };
|
||||
}
|
||||
|
||||
[Obsolete("Use 'object[index]' syntax instead")]
|
||||
public PgpSignature Get(int index)
|
||||
{
|
||||
return this[index];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using Org.BouncyCastle.Bcpg.Sig;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpSignatureSubpacketGenerator
|
||||
{
|
||||
private IList list = Platform.CreateArrayList();
|
||||
|
||||
public void SetRevocable(bool isCritical, bool isRevocable)
|
||||
{
|
||||
list.Add(new Revocable(isCritical, isRevocable));
|
||||
}
|
||||
|
||||
public void SetExportable(bool isCritical, bool isExportable)
|
||||
{
|
||||
list.Add(new Exportable(isCritical, isExportable));
|
||||
}
|
||||
|
||||
public void SetFeature(bool isCritical, byte feature)
|
||||
{
|
||||
list.Add(new Features(isCritical, feature));
|
||||
}
|
||||
|
||||
public void SetTrust(bool isCritical, int depth, int trustAmount)
|
||||
{
|
||||
list.Add(new TrustSignature(isCritical, depth, trustAmount));
|
||||
}
|
||||
|
||||
public void SetKeyExpirationTime(bool isCritical, long seconds)
|
||||
{
|
||||
list.Add(new KeyExpirationTime(isCritical, seconds));
|
||||
}
|
||||
|
||||
public void SetSignatureExpirationTime(bool isCritical, long seconds)
|
||||
{
|
||||
list.Add(new SignatureExpirationTime(isCritical, seconds));
|
||||
}
|
||||
|
||||
public void SetSignatureCreationTime(bool isCritical, DateTime date)
|
||||
{
|
||||
list.Add(new SignatureCreationTime(isCritical, date));
|
||||
}
|
||||
|
||||
public void SetPreferredHashAlgorithms(bool isCritical, int[] algorithms)
|
||||
{
|
||||
list.Add(new PreferredAlgorithms(SignatureSubpacketTag.PreferredHashAlgorithms, isCritical, algorithms));
|
||||
}
|
||||
|
||||
public void SetPreferredSymmetricAlgorithms(bool isCritical, int[] algorithms)
|
||||
{
|
||||
list.Add(new PreferredAlgorithms(SignatureSubpacketTag.PreferredSymmetricAlgorithms, isCritical, algorithms));
|
||||
}
|
||||
|
||||
public void SetPreferredCompressionAlgorithms(bool isCritical, int[] algorithms)
|
||||
{
|
||||
list.Add(new PreferredAlgorithms(SignatureSubpacketTag.PreferredCompressionAlgorithms, isCritical, algorithms));
|
||||
}
|
||||
|
||||
public void SetKeyFlags(bool isCritical, int flags)
|
||||
{
|
||||
list.Add(new KeyFlags(isCritical, flags));
|
||||
}
|
||||
|
||||
public void SetSignerUserId(bool isCritical, string userId)
|
||||
{
|
||||
if (userId == null)
|
||||
{
|
||||
throw new ArgumentNullException("userId");
|
||||
}
|
||||
list.Add(new SignerUserId(isCritical, userId));
|
||||
}
|
||||
|
||||
public void SetSignerUserId(bool isCritical, byte[] rawUserId)
|
||||
{
|
||||
if (rawUserId == null)
|
||||
{
|
||||
throw new ArgumentNullException("rawUserId");
|
||||
}
|
||||
list.Add(new SignerUserId(isCritical, isLongLength: false, rawUserId));
|
||||
}
|
||||
|
||||
public void SetEmbeddedSignature(bool isCritical, PgpSignature pgpSignature)
|
||||
{
|
||||
byte[] encoded = pgpSignature.GetEncoded();
|
||||
byte[] array = ((encoded.Length - 1 <= 256) ? new byte[encoded.Length - 2] : new byte[encoded.Length - 3]);
|
||||
Array.Copy(encoded, encoded.Length - array.Length, array, 0, array.Length);
|
||||
list.Add(new EmbeddedSignature(isCritical, isLongLength: false, array));
|
||||
}
|
||||
|
||||
public void SetPrimaryUserId(bool isCritical, bool isPrimaryUserId)
|
||||
{
|
||||
list.Add(new PrimaryUserId(isCritical, isPrimaryUserId));
|
||||
}
|
||||
|
||||
public void SetNotationData(bool isCritical, bool isHumanReadable, string notationName, string notationValue)
|
||||
{
|
||||
list.Add(new NotationData(isCritical, isHumanReadable, notationName, notationValue));
|
||||
}
|
||||
|
||||
public void SetRevocationReason(bool isCritical, RevocationReasonTag reason, string description)
|
||||
{
|
||||
list.Add(new RevocationReason(isCritical, reason, description));
|
||||
}
|
||||
|
||||
public void SetRevocationKey(bool isCritical, PublicKeyAlgorithmTag keyAlgorithm, byte[] fingerprint)
|
||||
{
|
||||
list.Add(new RevocationKey(isCritical, RevocationKeyTag.ClassDefault, keyAlgorithm, fingerprint));
|
||||
}
|
||||
|
||||
public void SetIssuerKeyID(bool isCritical, long keyID)
|
||||
{
|
||||
list.Add(new IssuerKeyId(isCritical, keyID));
|
||||
}
|
||||
|
||||
public PgpSignatureSubpacketVector Generate()
|
||||
{
|
||||
SignatureSubpacket[] array = new SignatureSubpacket[list.Count];
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
array[i] = (SignatureSubpacket)list[i];
|
||||
}
|
||||
return new PgpSignatureSubpacketVector(array);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
using System;
|
||||
using Org.BouncyCastle.Bcpg.Sig;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpSignatureSubpacketVector
|
||||
{
|
||||
private readonly SignatureSubpacket[] packets;
|
||||
|
||||
[Obsolete("Use 'Count' property instead")]
|
||||
public int Size => packets.Length;
|
||||
|
||||
public int Count => packets.Length;
|
||||
|
||||
internal PgpSignatureSubpacketVector(SignatureSubpacket[] packets)
|
||||
{
|
||||
this.packets = packets;
|
||||
}
|
||||
|
||||
public SignatureSubpacket GetSubpacket(SignatureSubpacketTag type)
|
||||
{
|
||||
for (int i = 0; i != packets.Length; i++)
|
||||
{
|
||||
if (packets[i].SubpacketType == type)
|
||||
{
|
||||
return packets[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool HasSubpacket(SignatureSubpacketTag type)
|
||||
{
|
||||
return GetSubpacket(type) != null;
|
||||
}
|
||||
|
||||
public SignatureSubpacket[] GetSubpackets(SignatureSubpacketTag type)
|
||||
{
|
||||
int num = 0;
|
||||
for (int i = 0; i < packets.Length; i++)
|
||||
{
|
||||
if (packets[i].SubpacketType == type)
|
||||
{
|
||||
num++;
|
||||
}
|
||||
}
|
||||
SignatureSubpacket[] array = new SignatureSubpacket[num];
|
||||
int num2 = 0;
|
||||
for (int j = 0; j < packets.Length; j++)
|
||||
{
|
||||
if (packets[j].SubpacketType == type)
|
||||
{
|
||||
array[num2++] = packets[j];
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
public NotationData[] GetNotationDataOccurrences()
|
||||
{
|
||||
SignatureSubpacket[] subpackets = GetSubpackets(SignatureSubpacketTag.NotationData);
|
||||
NotationData[] array = new NotationData[subpackets.Length];
|
||||
for (int i = 0; i < subpackets.Length; i++)
|
||||
{
|
||||
array[i] = (NotationData)subpackets[i];
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
[Obsolete("Use 'GetNotationDataOccurrences' instead")]
|
||||
public NotationData[] GetNotationDataOccurences()
|
||||
{
|
||||
return GetNotationDataOccurrences();
|
||||
}
|
||||
|
||||
public long GetIssuerKeyId()
|
||||
{
|
||||
SignatureSubpacket subpacket = GetSubpacket(SignatureSubpacketTag.IssuerKeyId);
|
||||
if (subpacket != null)
|
||||
{
|
||||
return ((IssuerKeyId)subpacket).KeyId;
|
||||
}
|
||||
return 0L;
|
||||
}
|
||||
|
||||
public bool HasSignatureCreationTime()
|
||||
{
|
||||
return GetSubpacket(SignatureSubpacketTag.CreationTime) != null;
|
||||
}
|
||||
|
||||
public DateTime GetSignatureCreationTime()
|
||||
{
|
||||
SignatureSubpacket subpacket = GetSubpacket(SignatureSubpacketTag.CreationTime);
|
||||
if (subpacket == null)
|
||||
{
|
||||
throw new PgpException("SignatureCreationTime not available");
|
||||
}
|
||||
return ((SignatureCreationTime)subpacket).GetTime();
|
||||
}
|
||||
|
||||
public long GetSignatureExpirationTime()
|
||||
{
|
||||
SignatureSubpacket subpacket = GetSubpacket(SignatureSubpacketTag.ExpireTime);
|
||||
if (subpacket != null)
|
||||
{
|
||||
return ((SignatureExpirationTime)subpacket).Time;
|
||||
}
|
||||
return 0L;
|
||||
}
|
||||
|
||||
public long GetKeyExpirationTime()
|
||||
{
|
||||
SignatureSubpacket subpacket = GetSubpacket(SignatureSubpacketTag.KeyExpireTime);
|
||||
if (subpacket != null)
|
||||
{
|
||||
return ((KeyExpirationTime)subpacket).Time;
|
||||
}
|
||||
return 0L;
|
||||
}
|
||||
|
||||
public int[] GetPreferredHashAlgorithms()
|
||||
{
|
||||
SignatureSubpacket subpacket = GetSubpacket(SignatureSubpacketTag.PreferredHashAlgorithms);
|
||||
if (subpacket != null)
|
||||
{
|
||||
return ((PreferredAlgorithms)subpacket).GetPreferences();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int[] GetPreferredSymmetricAlgorithms()
|
||||
{
|
||||
SignatureSubpacket subpacket = GetSubpacket(SignatureSubpacketTag.PreferredSymmetricAlgorithms);
|
||||
if (subpacket != null)
|
||||
{
|
||||
return ((PreferredAlgorithms)subpacket).GetPreferences();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int[] GetPreferredCompressionAlgorithms()
|
||||
{
|
||||
SignatureSubpacket subpacket = GetSubpacket(SignatureSubpacketTag.PreferredCompressionAlgorithms);
|
||||
if (subpacket != null)
|
||||
{
|
||||
return ((PreferredAlgorithms)subpacket).GetPreferences();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int GetKeyFlags()
|
||||
{
|
||||
SignatureSubpacket subpacket = GetSubpacket(SignatureSubpacketTag.KeyFlags);
|
||||
if (subpacket != null)
|
||||
{
|
||||
return ((KeyFlags)subpacket).Flags;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public string GetSignerUserId()
|
||||
{
|
||||
SignatureSubpacket subpacket = GetSubpacket(SignatureSubpacketTag.SignerUserId);
|
||||
if (subpacket != null)
|
||||
{
|
||||
return ((SignerUserId)subpacket).GetId();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool IsPrimaryUserId()
|
||||
{
|
||||
return ((PrimaryUserId)GetSubpacket(SignatureSubpacketTag.PrimaryUserId))?.IsPrimaryUserId() ?? false;
|
||||
}
|
||||
|
||||
public SignatureSubpacketTag[] GetCriticalTags()
|
||||
{
|
||||
int num = 0;
|
||||
for (int i = 0; i != packets.Length; i++)
|
||||
{
|
||||
if (packets[i].IsCritical())
|
||||
{
|
||||
num++;
|
||||
}
|
||||
}
|
||||
SignatureSubpacketTag[] array = new SignatureSubpacketTag[num];
|
||||
num = 0;
|
||||
for (int j = 0; j != packets.Length; j++)
|
||||
{
|
||||
if (packets[j].IsCritical())
|
||||
{
|
||||
array[num++] = packets[j].SubpacketType;
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
public Features GetFeatures()
|
||||
{
|
||||
SignatureSubpacket subpacket = GetSubpacket(SignatureSubpacketTag.Features);
|
||||
if (subpacket == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return new Features(subpacket.IsCritical(), subpacket.IsLongLength(), subpacket.GetData());
|
||||
}
|
||||
|
||||
internal SignatureSubpacket[] ToSubpacketArray()
|
||||
{
|
||||
return packets;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
using Org.BouncyCastle.Bcpg.Attr;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpUserAttributeSubpacketVector
|
||||
{
|
||||
private readonly UserAttributeSubpacket[] packets;
|
||||
|
||||
internal PgpUserAttributeSubpacketVector(UserAttributeSubpacket[] packets)
|
||||
{
|
||||
this.packets = packets;
|
||||
}
|
||||
|
||||
public UserAttributeSubpacket GetSubpacket(UserAttributeSubpacketTag type)
|
||||
{
|
||||
for (int i = 0; i != packets.Length; i++)
|
||||
{
|
||||
if (packets[i].SubpacketType == type)
|
||||
{
|
||||
return packets[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ImageAttrib GetImageAttribute()
|
||||
{
|
||||
UserAttributeSubpacket subpacket = GetSubpacket(UserAttributeSubpacketTag.ImageAttribute);
|
||||
if (subpacket != null)
|
||||
{
|
||||
return (ImageAttrib)subpacket;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
internal UserAttributeSubpacket[] ToSubpacketArray()
|
||||
{
|
||||
return packets;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == this)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (!(obj is PgpUserAttributeSubpacketVector pgpUserAttributeSubpacketVector))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (pgpUserAttributeSubpacketVector.packets.Length != packets.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i != packets.Length; i++)
|
||||
{
|
||||
if (!pgpUserAttributeSubpacketVector.packets[i].Equals(packets[i]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
int num = 0;
|
||||
UserAttributeSubpacket[] array = packets;
|
||||
foreach (object obj in array)
|
||||
{
|
||||
num ^= obj.GetHashCode();
|
||||
}
|
||||
return num;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using Org.BouncyCastle.Bcpg.Attr;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpUserAttributeSubpacketVectorGenerator
|
||||
{
|
||||
private IList list = Platform.CreateArrayList();
|
||||
|
||||
public virtual void SetImageAttribute(ImageAttrib.Format imageType, byte[] imageData)
|
||||
{
|
||||
if (imageData == null)
|
||||
{
|
||||
throw new ArgumentException("attempt to set null image", "imageData");
|
||||
}
|
||||
list.Add(new ImageAttrib(imageType, imageData));
|
||||
}
|
||||
|
||||
public virtual PgpUserAttributeSubpacketVector Generate()
|
||||
{
|
||||
UserAttributeSubpacket[] array = new UserAttributeSubpacket[list.Count];
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
array[i] = (UserAttributeSubpacket)list[i];
|
||||
}
|
||||
return new PgpUserAttributeSubpacketVector(array);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,419 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Org.BouncyCastle.Asn1;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Math;
|
||||
using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
using Org.BouncyCastle.Utilities.Encoders;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public sealed class PgpUtilities
|
||||
{
|
||||
private const int ReadAhead = 60;
|
||||
|
||||
private PgpUtilities()
|
||||
{
|
||||
}
|
||||
|
||||
public static MPInteger[] DsaSigToMpi(byte[] encoding)
|
||||
{
|
||||
DerInteger derInteger;
|
||||
DerInteger derInteger2;
|
||||
try
|
||||
{
|
||||
Asn1Sequence asn1Sequence = (Asn1Sequence)Asn1Object.FromByteArray(encoding);
|
||||
derInteger = (DerInteger)asn1Sequence[0];
|
||||
derInteger2 = (DerInteger)asn1Sequence[1];
|
||||
}
|
||||
catch (IOException exception)
|
||||
{
|
||||
throw new PgpException("exception encoding signature", exception);
|
||||
}
|
||||
return new MPInteger[2]
|
||||
{
|
||||
new MPInteger(derInteger.Value),
|
||||
new MPInteger(derInteger2.Value)
|
||||
};
|
||||
}
|
||||
|
||||
public static MPInteger[] RsaSigToMpi(byte[] encoding)
|
||||
{
|
||||
return new MPInteger[1]
|
||||
{
|
||||
new MPInteger(new BigInteger(1, encoding))
|
||||
};
|
||||
}
|
||||
|
||||
public static string GetDigestName(HashAlgorithmTag hashAlgorithm)
|
||||
{
|
||||
return hashAlgorithm switch
|
||||
{
|
||||
HashAlgorithmTag.Sha1 => "SHA1",
|
||||
HashAlgorithmTag.MD2 => "MD2",
|
||||
HashAlgorithmTag.MD5 => "MD5",
|
||||
HashAlgorithmTag.RipeMD160 => "RIPEMD160",
|
||||
HashAlgorithmTag.Sha224 => "SHA224",
|
||||
HashAlgorithmTag.Sha256 => "SHA256",
|
||||
HashAlgorithmTag.Sha384 => "SHA384",
|
||||
HashAlgorithmTag.Sha512 => "SHA512",
|
||||
_ => throw new PgpException("unknown hash algorithm tag in GetDigestName: " + hashAlgorithm),
|
||||
};
|
||||
}
|
||||
|
||||
public static string GetSignatureName(PublicKeyAlgorithmTag keyAlgorithm, HashAlgorithmTag hashAlgorithm)
|
||||
{
|
||||
string text;
|
||||
switch (keyAlgorithm)
|
||||
{
|
||||
case PublicKeyAlgorithmTag.RsaGeneral:
|
||||
case PublicKeyAlgorithmTag.RsaSign:
|
||||
text = "RSA";
|
||||
break;
|
||||
case PublicKeyAlgorithmTag.Dsa:
|
||||
text = "DSA";
|
||||
break;
|
||||
case PublicKeyAlgorithmTag.EC:
|
||||
text = "ECDH";
|
||||
break;
|
||||
case PublicKeyAlgorithmTag.ECDsa:
|
||||
text = "ECDSA";
|
||||
break;
|
||||
case PublicKeyAlgorithmTag.ElGamalEncrypt:
|
||||
case PublicKeyAlgorithmTag.ElGamalGeneral:
|
||||
text = "ElGamal";
|
||||
break;
|
||||
default:
|
||||
throw new PgpException("unknown algorithm tag in signature:" + keyAlgorithm);
|
||||
}
|
||||
return GetDigestName(hashAlgorithm) + "with" + text;
|
||||
}
|
||||
|
||||
public static string GetSymmetricCipherName(SymmetricKeyAlgorithmTag algorithm)
|
||||
{
|
||||
return algorithm switch
|
||||
{
|
||||
SymmetricKeyAlgorithmTag.Null => null,
|
||||
SymmetricKeyAlgorithmTag.TripleDes => "DESEDE",
|
||||
SymmetricKeyAlgorithmTag.Idea => "IDEA",
|
||||
SymmetricKeyAlgorithmTag.Cast5 => "CAST5",
|
||||
SymmetricKeyAlgorithmTag.Blowfish => "Blowfish",
|
||||
SymmetricKeyAlgorithmTag.Safer => "SAFER",
|
||||
SymmetricKeyAlgorithmTag.Des => "DES",
|
||||
SymmetricKeyAlgorithmTag.Aes128 => "AES",
|
||||
SymmetricKeyAlgorithmTag.Aes192 => "AES",
|
||||
SymmetricKeyAlgorithmTag.Aes256 => "AES",
|
||||
SymmetricKeyAlgorithmTag.Twofish => "Twofish",
|
||||
SymmetricKeyAlgorithmTag.Camellia128 => "Camellia",
|
||||
SymmetricKeyAlgorithmTag.Camellia192 => "Camellia",
|
||||
SymmetricKeyAlgorithmTag.Camellia256 => "Camellia",
|
||||
_ => throw new PgpException("unknown symmetric algorithm: " + algorithm),
|
||||
};
|
||||
}
|
||||
|
||||
public static int GetKeySize(SymmetricKeyAlgorithmTag algorithm)
|
||||
{
|
||||
switch (algorithm)
|
||||
{
|
||||
case SymmetricKeyAlgorithmTag.Des:
|
||||
return 64;
|
||||
case SymmetricKeyAlgorithmTag.Idea:
|
||||
case SymmetricKeyAlgorithmTag.Cast5:
|
||||
case SymmetricKeyAlgorithmTag.Blowfish:
|
||||
case SymmetricKeyAlgorithmTag.Safer:
|
||||
case SymmetricKeyAlgorithmTag.Aes128:
|
||||
case SymmetricKeyAlgorithmTag.Camellia128:
|
||||
return 128;
|
||||
case SymmetricKeyAlgorithmTag.TripleDes:
|
||||
case SymmetricKeyAlgorithmTag.Aes192:
|
||||
case SymmetricKeyAlgorithmTag.Camellia192:
|
||||
return 192;
|
||||
case SymmetricKeyAlgorithmTag.Aes256:
|
||||
case SymmetricKeyAlgorithmTag.Twofish:
|
||||
case SymmetricKeyAlgorithmTag.Camellia256:
|
||||
return 256;
|
||||
default:
|
||||
throw new PgpException("unknown symmetric algorithm: " + algorithm);
|
||||
}
|
||||
}
|
||||
|
||||
public static KeyParameter MakeKey(SymmetricKeyAlgorithmTag algorithm, byte[] keyBytes)
|
||||
{
|
||||
string symmetricCipherName = GetSymmetricCipherName(algorithm);
|
||||
return ParameterUtilities.CreateKeyParameter(symmetricCipherName, keyBytes);
|
||||
}
|
||||
|
||||
public static KeyParameter MakeRandomKey(SymmetricKeyAlgorithmTag algorithm, SecureRandom random)
|
||||
{
|
||||
int keySize = GetKeySize(algorithm);
|
||||
byte[] array = new byte[(keySize + 7) / 8];
|
||||
random.NextBytes(array);
|
||||
return MakeKey(algorithm, array);
|
||||
}
|
||||
|
||||
internal static byte[] EncodePassPhrase(char[] passPhrase, bool utf8)
|
||||
{
|
||||
if (passPhrase != null)
|
||||
{
|
||||
if (!utf8)
|
||||
{
|
||||
return Strings.ToByteArray(passPhrase);
|
||||
}
|
||||
return Encoding.UTF8.GetBytes(passPhrase);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static KeyParameter MakeKeyFromPassPhrase(SymmetricKeyAlgorithmTag algorithm, S2k s2k, char[] passPhrase)
|
||||
{
|
||||
return DoMakeKeyFromPassPhrase(algorithm, s2k, EncodePassPhrase(passPhrase, utf8: false), clearPassPhrase: true);
|
||||
}
|
||||
|
||||
public static KeyParameter MakeKeyFromPassPhraseUtf8(SymmetricKeyAlgorithmTag algorithm, S2k s2k, char[] passPhrase)
|
||||
{
|
||||
return DoMakeKeyFromPassPhrase(algorithm, s2k, EncodePassPhrase(passPhrase, utf8: true), clearPassPhrase: true);
|
||||
}
|
||||
|
||||
public static KeyParameter MakeKeyFromPassPhraseRaw(SymmetricKeyAlgorithmTag algorithm, S2k s2k, byte[] rawPassPhrase)
|
||||
{
|
||||
return DoMakeKeyFromPassPhrase(algorithm, s2k, rawPassPhrase, clearPassPhrase: false);
|
||||
}
|
||||
|
||||
internal static KeyParameter DoMakeKeyFromPassPhrase(SymmetricKeyAlgorithmTag algorithm, S2k s2k, byte[] rawPassPhrase, bool clearPassPhrase)
|
||||
{
|
||||
int keySize = GetKeySize(algorithm);
|
||||
byte[] array = new byte[(keySize + 7) / 8];
|
||||
int num = 0;
|
||||
int num2 = 0;
|
||||
while (num < array.Length)
|
||||
{
|
||||
IDigest digest;
|
||||
if (s2k != null)
|
||||
{
|
||||
string digestName = GetDigestName(s2k.HashAlgorithm);
|
||||
try
|
||||
{
|
||||
digest = DigestUtilities.GetDigest(digestName);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw new PgpException("can't find S2k digest", exception);
|
||||
}
|
||||
for (int i = 0; i != num2; i++)
|
||||
{
|
||||
digest.Update(0);
|
||||
}
|
||||
byte[] iV = s2k.GetIV();
|
||||
switch (s2k.Type)
|
||||
{
|
||||
case 0:
|
||||
digest.BlockUpdate(rawPassPhrase, 0, rawPassPhrase.Length);
|
||||
break;
|
||||
case 1:
|
||||
digest.BlockUpdate(iV, 0, iV.Length);
|
||||
digest.BlockUpdate(rawPassPhrase, 0, rawPassPhrase.Length);
|
||||
break;
|
||||
case 3:
|
||||
{
|
||||
long iterationCount = s2k.IterationCount;
|
||||
digest.BlockUpdate(iV, 0, iV.Length);
|
||||
digest.BlockUpdate(rawPassPhrase, 0, rawPassPhrase.Length);
|
||||
iterationCount -= iV.Length + rawPassPhrase.Length;
|
||||
while (iterationCount > 0)
|
||||
{
|
||||
if (iterationCount < iV.Length)
|
||||
{
|
||||
digest.BlockUpdate(iV, 0, (int)iterationCount);
|
||||
break;
|
||||
}
|
||||
digest.BlockUpdate(iV, 0, iV.Length);
|
||||
iterationCount -= iV.Length;
|
||||
if (iterationCount < rawPassPhrase.Length)
|
||||
{
|
||||
digest.BlockUpdate(rawPassPhrase, 0, (int)iterationCount);
|
||||
iterationCount = 0L;
|
||||
}
|
||||
else
|
||||
{
|
||||
digest.BlockUpdate(rawPassPhrase, 0, rawPassPhrase.Length);
|
||||
iterationCount -= rawPassPhrase.Length;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new PgpException("unknown S2k type: " + s2k.Type);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
digest = DigestUtilities.GetDigest("MD5");
|
||||
for (int j = 0; j != num2; j++)
|
||||
{
|
||||
digest.Update(0);
|
||||
}
|
||||
digest.BlockUpdate(rawPassPhrase, 0, rawPassPhrase.Length);
|
||||
}
|
||||
catch (Exception exception2)
|
||||
{
|
||||
throw new PgpException("can't find MD5 digest", exception2);
|
||||
}
|
||||
}
|
||||
byte[] array2 = DigestUtilities.DoFinal(digest);
|
||||
if (array2.Length > array.Length - num)
|
||||
{
|
||||
Array.Copy(array2, 0, array, num, array.Length - num);
|
||||
}
|
||||
else
|
||||
{
|
||||
Array.Copy(array2, 0, array, num, array2.Length);
|
||||
}
|
||||
num += array2.Length;
|
||||
num2++;
|
||||
}
|
||||
if (clearPassPhrase && rawPassPhrase != null)
|
||||
{
|
||||
Array.Clear(rawPassPhrase, 0, rawPassPhrase.Length);
|
||||
}
|
||||
return MakeKey(algorithm, array);
|
||||
}
|
||||
|
||||
public static void WriteFileToLiteralData(Stream output, char fileType, FileInfo file)
|
||||
{
|
||||
PgpLiteralDataGenerator pgpLiteralDataGenerator = new PgpLiteralDataGenerator();
|
||||
Stream pOut = pgpLiteralDataGenerator.Open(output, fileType, file.Name, file.Length, file.LastWriteTime);
|
||||
PipeFileContents(file, pOut, 32768);
|
||||
}
|
||||
|
||||
public static void WriteFileToLiteralData(Stream output, char fileType, FileInfo file, byte[] buffer)
|
||||
{
|
||||
PgpLiteralDataGenerator pgpLiteralDataGenerator = new PgpLiteralDataGenerator();
|
||||
Stream pOut = pgpLiteralDataGenerator.Open(output, fileType, file.Name, file.LastWriteTime, buffer);
|
||||
PipeFileContents(file, pOut, buffer.Length);
|
||||
}
|
||||
|
||||
private static void PipeFileContents(FileInfo file, Stream pOut, int bufSize)
|
||||
{
|
||||
FileStream fileStream = file.OpenRead();
|
||||
byte[] array = new byte[bufSize];
|
||||
try
|
||||
{
|
||||
int count;
|
||||
while ((count = fileStream.Read(array, 0, array.Length)) > 0)
|
||||
{
|
||||
pOut.Write(array, 0, count);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Array.Clear(array, 0, array.Length);
|
||||
Platform.Dispose(pOut);
|
||||
Platform.Dispose(fileStream);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsPossiblyBase64(int ch)
|
||||
{
|
||||
if ((ch < 65 || ch > 90) && (ch < 97 || ch > 122) && (ch < 48 || ch > 57) && ch != 43 && ch != 47 && ch != 13)
|
||||
{
|
||||
return ch == 10;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static Stream GetDecoderStream(Stream inputStream)
|
||||
{
|
||||
if (!inputStream.CanSeek)
|
||||
{
|
||||
throw new ArgumentException("inputStream must be seek-able", "inputStream");
|
||||
}
|
||||
long position = inputStream.Position;
|
||||
int num = inputStream.ReadByte();
|
||||
if ((num & 0x80) != 0)
|
||||
{
|
||||
inputStream.Position = position;
|
||||
return inputStream;
|
||||
}
|
||||
if (!IsPossiblyBase64(num))
|
||||
{
|
||||
inputStream.Position = position;
|
||||
return new ArmoredInputStream(inputStream);
|
||||
}
|
||||
byte[] array = new byte[60];
|
||||
int i = 1;
|
||||
int num2 = 1;
|
||||
array[0] = (byte)num;
|
||||
for (; i != 60; i++)
|
||||
{
|
||||
if ((num = inputStream.ReadByte()) < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (!IsPossiblyBase64(num))
|
||||
{
|
||||
inputStream.Position = position;
|
||||
return new ArmoredInputStream(inputStream);
|
||||
}
|
||||
if (num != 10 && num != 13)
|
||||
{
|
||||
array[num2++] = (byte)num;
|
||||
}
|
||||
}
|
||||
inputStream.Position = position;
|
||||
if (i < 4)
|
||||
{
|
||||
return new ArmoredInputStream(inputStream);
|
||||
}
|
||||
byte[] array2 = new byte[8];
|
||||
Array.Copy(array, 0, array2, 0, array2.Length);
|
||||
try
|
||||
{
|
||||
byte[] array3 = Base64.Decode(array2);
|
||||
bool hasHeaders = (array3[0] & 0x80) == 0;
|
||||
return new ArmoredInputStream(inputStream, hasHeaders);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
catch (Exception ex2)
|
||||
{
|
||||
throw new IOException(ex2.Message);
|
||||
}
|
||||
}
|
||||
|
||||
internal static IWrapper CreateWrapper(SymmetricKeyAlgorithmTag encAlgorithm)
|
||||
{
|
||||
switch (encAlgorithm)
|
||||
{
|
||||
case SymmetricKeyAlgorithmTag.Aes128:
|
||||
case SymmetricKeyAlgorithmTag.Aes192:
|
||||
case SymmetricKeyAlgorithmTag.Aes256:
|
||||
return WrapperUtilities.GetWrapper("AESWRAP");
|
||||
case SymmetricKeyAlgorithmTag.Camellia128:
|
||||
case SymmetricKeyAlgorithmTag.Camellia192:
|
||||
case SymmetricKeyAlgorithmTag.Camellia256:
|
||||
return WrapperUtilities.GetWrapper("CAMELLIAWRAP");
|
||||
default:
|
||||
throw new PgpException("unknown wrap algorithm: " + encAlgorithm);
|
||||
}
|
||||
}
|
||||
|
||||
internal static byte[] GenerateIV(int length, SecureRandom random)
|
||||
{
|
||||
byte[] array = new byte[length];
|
||||
random.NextBytes(array);
|
||||
return array;
|
||||
}
|
||||
|
||||
internal static S2k GenerateS2k(HashAlgorithmTag hashAlgorithm, int s2kCount, SecureRandom random)
|
||||
{
|
||||
byte[] iv = GenerateIV(8, random);
|
||||
return new S2k(hashAlgorithm, iv, s2kCount);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Utilities.Date;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpV3SignatureGenerator
|
||||
{
|
||||
private PublicKeyAlgorithmTag keyAlgorithm;
|
||||
|
||||
private HashAlgorithmTag hashAlgorithm;
|
||||
|
||||
private PgpPrivateKey privKey;
|
||||
|
||||
private ISigner sig;
|
||||
|
||||
private IDigest dig;
|
||||
|
||||
private int signatureType;
|
||||
|
||||
private byte lastb;
|
||||
|
||||
public PgpV3SignatureGenerator(PublicKeyAlgorithmTag keyAlgorithm, HashAlgorithmTag hashAlgorithm)
|
||||
{
|
||||
this.keyAlgorithm = keyAlgorithm;
|
||||
this.hashAlgorithm = hashAlgorithm;
|
||||
dig = DigestUtilities.GetDigest(PgpUtilities.GetDigestName(hashAlgorithm));
|
||||
sig = SignerUtilities.GetSigner(PgpUtilities.GetSignatureName(keyAlgorithm, hashAlgorithm));
|
||||
}
|
||||
|
||||
public void InitSign(int sigType, PgpPrivateKey key)
|
||||
{
|
||||
InitSign(sigType, key, null);
|
||||
}
|
||||
|
||||
public void InitSign(int sigType, PgpPrivateKey key, SecureRandom random)
|
||||
{
|
||||
privKey = key;
|
||||
signatureType = sigType;
|
||||
try
|
||||
{
|
||||
ICipherParameters parameters = key.Key;
|
||||
if (random != null)
|
||||
{
|
||||
parameters = new ParametersWithRandom(key.Key, random);
|
||||
}
|
||||
sig.Init(forSigning: true, parameters);
|
||||
}
|
||||
catch (InvalidKeyException exception)
|
||||
{
|
||||
throw new PgpException("invalid key.", exception);
|
||||
}
|
||||
dig.Reset();
|
||||
lastb = 0;
|
||||
}
|
||||
|
||||
public void Update(byte b)
|
||||
{
|
||||
if (signatureType == 1)
|
||||
{
|
||||
doCanonicalUpdateByte(b);
|
||||
}
|
||||
else
|
||||
{
|
||||
doUpdateByte(b);
|
||||
}
|
||||
}
|
||||
|
||||
private void doCanonicalUpdateByte(byte b)
|
||||
{
|
||||
switch (b)
|
||||
{
|
||||
case 13:
|
||||
doUpdateCRLF();
|
||||
break;
|
||||
case 10:
|
||||
if (lastb != 13)
|
||||
{
|
||||
doUpdateCRLF();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
doUpdateByte(b);
|
||||
break;
|
||||
}
|
||||
lastb = b;
|
||||
}
|
||||
|
||||
private void doUpdateCRLF()
|
||||
{
|
||||
doUpdateByte(13);
|
||||
doUpdateByte(10);
|
||||
}
|
||||
|
||||
private void doUpdateByte(byte b)
|
||||
{
|
||||
sig.Update(b);
|
||||
dig.Update(b);
|
||||
}
|
||||
|
||||
public void Update(byte[] b)
|
||||
{
|
||||
if (signatureType == 1)
|
||||
{
|
||||
for (int i = 0; i != b.Length; i++)
|
||||
{
|
||||
doCanonicalUpdateByte(b[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sig.BlockUpdate(b, 0, b.Length);
|
||||
dig.BlockUpdate(b, 0, b.Length);
|
||||
}
|
||||
}
|
||||
|
||||
public void Update(byte[] b, int off, int len)
|
||||
{
|
||||
if (signatureType == 1)
|
||||
{
|
||||
int num = off + len;
|
||||
for (int i = off; i != num; i++)
|
||||
{
|
||||
doCanonicalUpdateByte(b[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sig.BlockUpdate(b, off, len);
|
||||
dig.BlockUpdate(b, off, len);
|
||||
}
|
||||
}
|
||||
|
||||
public PgpOnePassSignature GenerateOnePassVersion(bool isNested)
|
||||
{
|
||||
return new PgpOnePassSignature(new OnePassSignaturePacket(signatureType, hashAlgorithm, keyAlgorithm, privKey.KeyId, isNested));
|
||||
}
|
||||
|
||||
public PgpSignature Generate()
|
||||
{
|
||||
long num = DateTimeUtilities.CurrentUnixMs() / 1000;
|
||||
byte[] array = new byte[5]
|
||||
{
|
||||
(byte)signatureType,
|
||||
(byte)(num >> 24),
|
||||
(byte)(num >> 16),
|
||||
(byte)(num >> 8),
|
||||
(byte)num
|
||||
};
|
||||
sig.BlockUpdate(array, 0, array.Length);
|
||||
dig.BlockUpdate(array, 0, array.Length);
|
||||
byte[] encoding = sig.GenerateSignature();
|
||||
byte[] array2 = DigestUtilities.DoFinal(dig);
|
||||
byte[] fingerprint = new byte[2]
|
||||
{
|
||||
array2[0],
|
||||
array2[1]
|
||||
};
|
||||
MPInteger[] signature = ((keyAlgorithm == PublicKeyAlgorithmTag.RsaSign || keyAlgorithm == PublicKeyAlgorithmTag.RsaGeneral) ? PgpUtilities.RsaSigToMpi(encoding) : PgpUtilities.DsaSigToMpi(encoding));
|
||||
return new PgpSignature(new SignaturePacket(3, signatureType, privKey.KeyId, keyAlgorithm, hashAlgorithm, num * 1000, fingerprint, signature));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Asn1;
|
||||
using Org.BouncyCastle.Asn1.Nist;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Math.EC;
|
||||
using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
using Org.BouncyCastle.Utilities.Encoders;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public sealed class Rfc6637Utilities
|
||||
{
|
||||
private static readonly byte[] ANONYMOUS_SENDER = Hex.Decode("416E6F6E796D6F75732053656E64657220202020");
|
||||
|
||||
private Rfc6637Utilities()
|
||||
{
|
||||
}
|
||||
|
||||
public static string GetAgreementAlgorithm(PublicKeyPacket pubKeyData)
|
||||
{
|
||||
ECDHPublicBcpgKey eCDHPublicBcpgKey = (ECDHPublicBcpgKey)pubKeyData.Key;
|
||||
return eCDHPublicBcpgKey.HashAlgorithm switch
|
||||
{
|
||||
HashAlgorithmTag.Sha256 => "ECCDHwithSHA256CKDF",
|
||||
HashAlgorithmTag.Sha384 => "ECCDHwithSHA384CKDF",
|
||||
HashAlgorithmTag.Sha512 => "ECCDHwithSHA512CKDF",
|
||||
_ => throw new ArgumentException("Unknown hash algorithm specified: " + eCDHPublicBcpgKey.HashAlgorithm),
|
||||
};
|
||||
}
|
||||
|
||||
public static DerObjectIdentifier GetKeyEncryptionOID(SymmetricKeyAlgorithmTag algID)
|
||||
{
|
||||
return algID switch
|
||||
{
|
||||
SymmetricKeyAlgorithmTag.Aes128 => NistObjectIdentifiers.IdAes128Wrap,
|
||||
SymmetricKeyAlgorithmTag.Aes192 => NistObjectIdentifiers.IdAes192Wrap,
|
||||
SymmetricKeyAlgorithmTag.Aes256 => NistObjectIdentifiers.IdAes256Wrap,
|
||||
_ => throw new PgpException("unknown symmetric algorithm ID: " + algID),
|
||||
};
|
||||
}
|
||||
|
||||
public static int GetKeyLength(SymmetricKeyAlgorithmTag algID)
|
||||
{
|
||||
return algID switch
|
||||
{
|
||||
SymmetricKeyAlgorithmTag.Aes128 => 16,
|
||||
SymmetricKeyAlgorithmTag.Aes192 => 24,
|
||||
SymmetricKeyAlgorithmTag.Aes256 => 32,
|
||||
_ => throw new PgpException("unknown symmetric algorithm ID: " + algID),
|
||||
};
|
||||
}
|
||||
|
||||
public static byte[] CreateKey(PublicKeyPacket pubKeyData, ECPoint s)
|
||||
{
|
||||
byte[] parameters = CreateUserKeyingMaterial(pubKeyData);
|
||||
ECDHPublicBcpgKey eCDHPublicBcpgKey = (ECDHPublicBcpgKey)pubKeyData.Key;
|
||||
return Kdf(eCDHPublicBcpgKey.HashAlgorithm, s, GetKeyLength(eCDHPublicBcpgKey.SymmetricKeyAlgorithm), parameters);
|
||||
}
|
||||
|
||||
public static byte[] CreateUserKeyingMaterial(PublicKeyPacket pubKeyData)
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
ECDHPublicBcpgKey eCDHPublicBcpgKey = (ECDHPublicBcpgKey)pubKeyData.Key;
|
||||
byte[] encoded = eCDHPublicBcpgKey.CurveOid.GetEncoded();
|
||||
memoryStream.Write(encoded, 1, encoded.Length - 1);
|
||||
memoryStream.WriteByte((byte)pubKeyData.Algorithm);
|
||||
memoryStream.WriteByte(3);
|
||||
memoryStream.WriteByte(1);
|
||||
memoryStream.WriteByte((byte)eCDHPublicBcpgKey.HashAlgorithm);
|
||||
memoryStream.WriteByte((byte)eCDHPublicBcpgKey.SymmetricKeyAlgorithm);
|
||||
memoryStream.Write(ANONYMOUS_SENDER, 0, ANONYMOUS_SENDER.Length);
|
||||
byte[] array = PgpPublicKey.CalculateFingerprint(pubKeyData);
|
||||
memoryStream.Write(array, 0, array.Length);
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
|
||||
private static byte[] Kdf(HashAlgorithmTag digestAlg, ECPoint s, int keyLen, byte[] parameters)
|
||||
{
|
||||
byte[] encoded = s.XCoord.GetEncoded();
|
||||
string digestName = PgpUtilities.GetDigestName(digestAlg);
|
||||
IDigest digest = DigestUtilities.GetDigest(digestName);
|
||||
digest.Update(0);
|
||||
digest.Update(0);
|
||||
digest.Update(0);
|
||||
digest.Update(1);
|
||||
digest.BlockUpdate(encoded, 0, encoded.Length);
|
||||
digest.BlockUpdate(parameters, 0, parameters.Length);
|
||||
byte[] data = DigestUtilities.DoFinal(digest);
|
||||
return Arrays.CopyOfRange(data, 0, keyLen);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Utilities.IO;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public sealed class SXprUtilities
|
||||
{
|
||||
private class MyS2k : S2k
|
||||
{
|
||||
private readonly long mIterationCount64;
|
||||
|
||||
public override long IterationCount => mIterationCount64;
|
||||
|
||||
internal MyS2k(HashAlgorithmTag algorithm, byte[] iv, long iterationCount64)
|
||||
: base(algorithm, iv, (int)iterationCount64)
|
||||
{
|
||||
mIterationCount64 = iterationCount64;
|
||||
}
|
||||
}
|
||||
|
||||
private SXprUtilities()
|
||||
{
|
||||
}
|
||||
|
||||
private static int ReadLength(Stream input, int ch)
|
||||
{
|
||||
int num = ch - 48;
|
||||
while ((ch = input.ReadByte()) >= 0 && ch != 58)
|
||||
{
|
||||
num = num * 10 + ch - 48;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
internal static string ReadString(Stream input, int ch)
|
||||
{
|
||||
int num = ReadLength(input, ch);
|
||||
char[] array = new char[num];
|
||||
for (int i = 0; i != array.Length; i++)
|
||||
{
|
||||
array[i] = (char)input.ReadByte();
|
||||
}
|
||||
return new string(array);
|
||||
}
|
||||
|
||||
internal static byte[] ReadBytes(Stream input, int ch)
|
||||
{
|
||||
int num = ReadLength(input, ch);
|
||||
byte[] array = new byte[num];
|
||||
Streams.ReadFully(input, array);
|
||||
return array;
|
||||
}
|
||||
|
||||
internal static S2k ParseS2k(Stream input)
|
||||
{
|
||||
SkipOpenParenthesis(input);
|
||||
ReadString(input, input.ReadByte());
|
||||
byte[] iv = ReadBytes(input, input.ReadByte());
|
||||
long iterationCount = long.Parse(ReadString(input, input.ReadByte()));
|
||||
SkipCloseParenthesis(input);
|
||||
return new MyS2k(HashAlgorithmTag.Sha1, iv, iterationCount);
|
||||
}
|
||||
|
||||
internal static void SkipOpenParenthesis(Stream input)
|
||||
{
|
||||
int num = input.ReadByte();
|
||||
if (num != 40)
|
||||
{
|
||||
throw new IOException("unknown character encountered");
|
||||
}
|
||||
}
|
||||
|
||||
internal static void SkipCloseParenthesis(Stream input)
|
||||
{
|
||||
int num = input.ReadByte();
|
||||
if (num != 41)
|
||||
{
|
||||
throw new IOException("unknown character encountered");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Utilities.IO;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class WrappedGeneratorStream : FilterStream
|
||||
{
|
||||
private readonly IStreamGenerator gen;
|
||||
|
||||
public WrappedGeneratorStream(IStreamGenerator gen, Stream str)
|
||||
: base(str)
|
||||
{
|
||||
this.gen = gen;
|
||||
}
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
gen.Close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public abstract class OutputStreamPacket
|
||||
{
|
||||
private readonly BcpgOutputStream bcpgOut;
|
||||
|
||||
internal OutputStreamPacket(BcpgOutputStream bcpgOut)
|
||||
{
|
||||
if (bcpgOut == null)
|
||||
{
|
||||
throw new ArgumentNullException("bcpgOut");
|
||||
}
|
||||
this.bcpgOut = bcpgOut;
|
||||
}
|
||||
|
||||
public abstract BcpgOutputStream Open();
|
||||
|
||||
public abstract void Close();
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public class Packet
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public enum PacketTag
|
||||
{
|
||||
Reserved = 0,
|
||||
PublicKeyEncryptedSession = 1,
|
||||
Signature = 2,
|
||||
SymmetricKeyEncryptedSessionKey = 3,
|
||||
OnePassSignature = 4,
|
||||
SecretKey = 5,
|
||||
PublicKey = 6,
|
||||
SecretSubkey = 7,
|
||||
CompressedData = 8,
|
||||
SymmetricKeyEncrypted = 9,
|
||||
Marker = 10,
|
||||
LiteralData = 11,
|
||||
Trust = 12,
|
||||
UserId = 13,
|
||||
PublicSubkey = 14,
|
||||
UserAttribute = 17,
|
||||
SymmetricEncryptedIntegrityProtected = 18,
|
||||
ModificationDetectionCode = 19,
|
||||
Experimental1 = 60,
|
||||
Experimental2 = 61,
|
||||
Experimental3 = 62,
|
||||
Experimental4 = 63
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public enum PublicKeyAlgorithmTag
|
||||
{
|
||||
RsaGeneral = 1,
|
||||
RsaEncrypt = 2,
|
||||
RsaSign = 3,
|
||||
ElGamalEncrypt = 16,
|
||||
Dsa = 17,
|
||||
[Obsolete("Use 'ECDH' instead")]
|
||||
EC = 18,
|
||||
ECDH = 18,
|
||||
ECDsa = 19,
|
||||
ElGamalGeneral = 20,
|
||||
DiffieHellman = 21,
|
||||
Experimental_1 = 100,
|
||||
Experimental_2 = 101,
|
||||
Experimental_3 = 102,
|
||||
Experimental_4 = 103,
|
||||
Experimental_5 = 104,
|
||||
Experimental_6 = 105,
|
||||
Experimental_7 = 106,
|
||||
Experimental_8 = 107,
|
||||
Experimental_9 = 108,
|
||||
Experimental_10 = 109,
|
||||
Experimental_11 = 110
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
using Org.BouncyCastle.Utilities.IO;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public class PublicKeyEncSessionPacket : ContainedPacket
|
||||
{
|
||||
private int version;
|
||||
|
||||
private long keyId;
|
||||
|
||||
private PublicKeyAlgorithmTag algorithm;
|
||||
|
||||
private byte[][] data;
|
||||
|
||||
public int Version => version;
|
||||
|
||||
public long KeyId => keyId;
|
||||
|
||||
public PublicKeyAlgorithmTag Algorithm => algorithm;
|
||||
|
||||
internal PublicKeyEncSessionPacket(BcpgInputStream bcpgIn)
|
||||
{
|
||||
version = bcpgIn.ReadByte();
|
||||
keyId |= (long)bcpgIn.ReadByte() << 56;
|
||||
keyId |= (long)bcpgIn.ReadByte() << 48;
|
||||
keyId |= (long)bcpgIn.ReadByte() << 40;
|
||||
keyId |= (long)bcpgIn.ReadByte() << 32;
|
||||
keyId |= (long)bcpgIn.ReadByte() << 24;
|
||||
keyId |= (long)bcpgIn.ReadByte() << 16;
|
||||
keyId |= (long)bcpgIn.ReadByte() << 8;
|
||||
keyId |= (uint)bcpgIn.ReadByte();
|
||||
algorithm = (PublicKeyAlgorithmTag)bcpgIn.ReadByte();
|
||||
switch (algorithm)
|
||||
{
|
||||
case PublicKeyAlgorithmTag.RsaGeneral:
|
||||
case PublicKeyAlgorithmTag.RsaEncrypt:
|
||||
data = new byte[1][] { new MPInteger(bcpgIn).GetEncoded() };
|
||||
break;
|
||||
case PublicKeyAlgorithmTag.ElGamalEncrypt:
|
||||
case PublicKeyAlgorithmTag.ElGamalGeneral:
|
||||
{
|
||||
MPInteger mPInteger = new MPInteger(bcpgIn);
|
||||
MPInteger mPInteger2 = new MPInteger(bcpgIn);
|
||||
data = new byte[2][]
|
||||
{
|
||||
mPInteger.GetEncoded(),
|
||||
mPInteger2.GetEncoded()
|
||||
};
|
||||
break;
|
||||
}
|
||||
case PublicKeyAlgorithmTag.EC:
|
||||
data = new byte[1][] { Streams.ReadAll(bcpgIn) };
|
||||
break;
|
||||
default:
|
||||
throw new IOException("unknown PGP public key algorithm encountered");
|
||||
}
|
||||
}
|
||||
|
||||
public PublicKeyEncSessionPacket(long keyId, PublicKeyAlgorithmTag algorithm, byte[][] data)
|
||||
{
|
||||
version = 3;
|
||||
this.keyId = keyId;
|
||||
this.algorithm = algorithm;
|
||||
this.data = new byte[data.Length][];
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
{
|
||||
this.data[i] = Arrays.Clone(data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[][] GetEncSessionKey()
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
public override void Encode(BcpgOutputStream bcpgOut)
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
BcpgOutputStream bcpgOutputStream = new BcpgOutputStream(memoryStream);
|
||||
bcpgOutputStream.WriteByte((byte)version);
|
||||
bcpgOutputStream.WriteLong(keyId);
|
||||
bcpgOutputStream.WriteByte((byte)algorithm);
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
{
|
||||
bcpgOutputStream.Write(data[i]);
|
||||
}
|
||||
Platform.Dispose(bcpgOutputStream);
|
||||
bcpgOut.WritePacket(PacketTag.PublicKeyEncryptedSession, memoryStream.ToArray(), oldFormat: true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Utilities.Date;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public class PublicKeyPacket : ContainedPacket
|
||||
{
|
||||
private int version;
|
||||
|
||||
private long time;
|
||||
|
||||
private int validDays;
|
||||
|
||||
private PublicKeyAlgorithmTag algorithm;
|
||||
|
||||
private IBcpgKey key;
|
||||
|
||||
public virtual int Version => version;
|
||||
|
||||
public virtual PublicKeyAlgorithmTag Algorithm => algorithm;
|
||||
|
||||
public virtual int ValidDays => validDays;
|
||||
|
||||
public virtual IBcpgKey Key => key;
|
||||
|
||||
internal PublicKeyPacket(BcpgInputStream bcpgIn)
|
||||
{
|
||||
version = bcpgIn.ReadByte();
|
||||
time = (uint)((bcpgIn.ReadByte() << 24) | (bcpgIn.ReadByte() << 16) | (bcpgIn.ReadByte() << 8) | bcpgIn.ReadByte());
|
||||
if (version <= 3)
|
||||
{
|
||||
validDays = (bcpgIn.ReadByte() << 8) | bcpgIn.ReadByte();
|
||||
}
|
||||
algorithm = (PublicKeyAlgorithmTag)bcpgIn.ReadByte();
|
||||
switch (algorithm)
|
||||
{
|
||||
case PublicKeyAlgorithmTag.RsaGeneral:
|
||||
case PublicKeyAlgorithmTag.RsaEncrypt:
|
||||
case PublicKeyAlgorithmTag.RsaSign:
|
||||
key = new RsaPublicBcpgKey(bcpgIn);
|
||||
break;
|
||||
case PublicKeyAlgorithmTag.Dsa:
|
||||
key = new DsaPublicBcpgKey(bcpgIn);
|
||||
break;
|
||||
case PublicKeyAlgorithmTag.ElGamalEncrypt:
|
||||
case PublicKeyAlgorithmTag.ElGamalGeneral:
|
||||
key = new ElGamalPublicBcpgKey(bcpgIn);
|
||||
break;
|
||||
case PublicKeyAlgorithmTag.EC:
|
||||
key = new ECDHPublicBcpgKey(bcpgIn);
|
||||
break;
|
||||
case PublicKeyAlgorithmTag.ECDsa:
|
||||
key = new ECDsaPublicBcpgKey(bcpgIn);
|
||||
break;
|
||||
default:
|
||||
throw new IOException("unknown PGP public key algorithm encountered");
|
||||
}
|
||||
}
|
||||
|
||||
public PublicKeyPacket(PublicKeyAlgorithmTag algorithm, DateTime time, IBcpgKey key)
|
||||
{
|
||||
version = 4;
|
||||
this.time = DateTimeUtilities.DateTimeToUnixMs(time) / 1000;
|
||||
this.algorithm = algorithm;
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public virtual DateTime GetTime()
|
||||
{
|
||||
return DateTimeUtilities.UnixMsToDateTime(time * 1000);
|
||||
}
|
||||
|
||||
public virtual byte[] GetEncodedContents()
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
BcpgOutputStream bcpgOutputStream = new BcpgOutputStream(memoryStream);
|
||||
bcpgOutputStream.WriteByte((byte)version);
|
||||
bcpgOutputStream.WriteInt((int)time);
|
||||
if (version <= 3)
|
||||
{
|
||||
bcpgOutputStream.WriteShort((short)validDays);
|
||||
}
|
||||
bcpgOutputStream.WriteByte((byte)algorithm);
|
||||
bcpgOutputStream.WriteObject((BcpgObject)key);
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
|
||||
public override void Encode(BcpgOutputStream bcpgOut)
|
||||
{
|
||||
bcpgOut.WritePacket(PacketTag.PublicKey, GetEncodedContents(), oldFormat: true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public class PublicSubkeyPacket : PublicKeyPacket
|
||||
{
|
||||
internal PublicSubkeyPacket(BcpgInputStream bcpgIn)
|
||||
: base(bcpgIn)
|
||||
{
|
||||
}
|
||||
|
||||
public PublicSubkeyPacket(PublicKeyAlgorithmTag algorithm, DateTime time, IBcpgKey key)
|
||||
: base(algorithm, time, key)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Encode(BcpgOutputStream bcpgOut)
|
||||
{
|
||||
bcpgOut.WritePacket(PacketTag.PublicSubkey, GetEncodedContents(), oldFormat: true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public class RevocationKey : SignatureSubpacket
|
||||
{
|
||||
public virtual RevocationKeyTag SignatureClass => (RevocationKeyTag)GetData()[0];
|
||||
|
||||
public virtual PublicKeyAlgorithmTag Algorithm => (PublicKeyAlgorithmTag)GetData()[1];
|
||||
|
||||
public RevocationKey(bool isCritical, bool isLongLength, byte[] data)
|
||||
: base(SignatureSubpacketTag.RevocationKey, isCritical, isLongLength, data)
|
||||
{
|
||||
}
|
||||
|
||||
public RevocationKey(bool isCritical, RevocationKeyTag signatureClass, PublicKeyAlgorithmTag keyAlgorithm, byte[] fingerprint)
|
||||
: base(SignatureSubpacketTag.RevocationKey, isCritical, isLongLength: false, CreateData(signatureClass, keyAlgorithm, fingerprint))
|
||||
{
|
||||
}
|
||||
|
||||
private static byte[] CreateData(RevocationKeyTag signatureClass, PublicKeyAlgorithmTag keyAlgorithm, byte[] fingerprint)
|
||||
{
|
||||
byte[] array = new byte[2 + fingerprint.Length];
|
||||
array[0] = (byte)signatureClass;
|
||||
array[1] = (byte)keyAlgorithm;
|
||||
Array.Copy(fingerprint, 0, array, 2, fingerprint.Length);
|
||||
return array;
|
||||
}
|
||||
|
||||
public virtual byte[] GetFingerprint()
|
||||
{
|
||||
byte[] array = GetData();
|
||||
byte[] array2 = new byte[array.Length - 2];
|
||||
Array.Copy(array, 2, array2, 0, array2.Length);
|
||||
return array2;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public enum RevocationKeyTag : byte
|
||||
{
|
||||
ClassDefault = 128,
|
||||
ClassSensitive = 64
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public class RevocationReason : SignatureSubpacket
|
||||
{
|
||||
public RevocationReason(bool isCritical, bool isLongLength, byte[] data)
|
||||
: base(SignatureSubpacketTag.RevocationReason, isCritical, isLongLength, data)
|
||||
{
|
||||
}
|
||||
|
||||
public RevocationReason(bool isCritical, RevocationReasonTag reason, string description)
|
||||
: base(SignatureSubpacketTag.RevocationReason, isCritical, isLongLength: false, CreateData(reason, description))
|
||||
{
|
||||
}
|
||||
|
||||
private static byte[] CreateData(RevocationReasonTag reason, string description)
|
||||
{
|
||||
byte[] array = Strings.ToUtf8ByteArray(description);
|
||||
byte[] array2 = new byte[1 + array.Length];
|
||||
array2[0] = (byte)reason;
|
||||
Array.Copy(array, 0, array2, 1, array.Length);
|
||||
return array2;
|
||||
}
|
||||
|
||||
public virtual RevocationReasonTag GetRevocationReason()
|
||||
{
|
||||
return (RevocationReasonTag)GetData()[0];
|
||||
}
|
||||
|
||||
public virtual string GetRevocationDescription()
|
||||
{
|
||||
byte[] array = GetData();
|
||||
if (array.Length == 1)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
byte[] array2 = new byte[array.Length - 1];
|
||||
Array.Copy(array, 1, array2, 0, array2.Length);
|
||||
return Strings.FromUtf8ByteArray(array2);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public enum RevocationReasonTag : byte
|
||||
{
|
||||
NoReason = 0,
|
||||
KeySuperseded = 1,
|
||||
KeyCompromised = 2,
|
||||
KeyRetired = 3,
|
||||
UserNoLongerValid = 32
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using Org.BouncyCastle.Math;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public class RsaPublicBcpgKey : BcpgObject, IBcpgKey
|
||||
{
|
||||
private readonly MPInteger n;
|
||||
|
||||
private readonly MPInteger e;
|
||||
|
||||
public BigInteger PublicExponent => e.Value;
|
||||
|
||||
public BigInteger Modulus => n.Value;
|
||||
|
||||
public string Format => "PGP";
|
||||
|
||||
public RsaPublicBcpgKey(BcpgInputStream bcpgIn)
|
||||
{
|
||||
n = new MPInteger(bcpgIn);
|
||||
e = new MPInteger(bcpgIn);
|
||||
}
|
||||
|
||||
public RsaPublicBcpgKey(BigInteger n, BigInteger e)
|
||||
{
|
||||
this.n = new MPInteger(n);
|
||||
this.e = new MPInteger(e);
|
||||
}
|
||||
|
||||
public override byte[] GetEncoded()
|
||||
{
|
||||
try
|
||||
{
|
||||
return base.GetEncoded();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Encode(BcpgOutputStream bcpgOut)
|
||||
{
|
||||
bcpgOut.WriteObjects(n, e);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
using System;
|
||||
using Org.BouncyCastle.Math;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public class RsaSecretBcpgKey : BcpgObject, IBcpgKey
|
||||
{
|
||||
private readonly MPInteger d;
|
||||
|
||||
private readonly MPInteger p;
|
||||
|
||||
private readonly MPInteger q;
|
||||
|
||||
private readonly MPInteger u;
|
||||
|
||||
private readonly BigInteger expP;
|
||||
|
||||
private readonly BigInteger expQ;
|
||||
|
||||
private readonly BigInteger crt;
|
||||
|
||||
public BigInteger Modulus => p.Value.Multiply(q.Value);
|
||||
|
||||
public BigInteger PrivateExponent => d.Value;
|
||||
|
||||
public BigInteger PrimeP => p.Value;
|
||||
|
||||
public BigInteger PrimeQ => q.Value;
|
||||
|
||||
public BigInteger PrimeExponentP => expP;
|
||||
|
||||
public BigInteger PrimeExponentQ => expQ;
|
||||
|
||||
public BigInteger CrtCoefficient => crt;
|
||||
|
||||
public string Format => "PGP";
|
||||
|
||||
public RsaSecretBcpgKey(BcpgInputStream bcpgIn)
|
||||
{
|
||||
d = new MPInteger(bcpgIn);
|
||||
p = new MPInteger(bcpgIn);
|
||||
q = new MPInteger(bcpgIn);
|
||||
u = new MPInteger(bcpgIn);
|
||||
expP = d.Value.Remainder(p.Value.Subtract(BigInteger.One));
|
||||
expQ = d.Value.Remainder(q.Value.Subtract(BigInteger.One));
|
||||
crt = q.Value.ModInverse(p.Value);
|
||||
}
|
||||
|
||||
public RsaSecretBcpgKey(BigInteger d, BigInteger p, BigInteger q)
|
||||
{
|
||||
int num = p.CompareTo(q);
|
||||
if (num >= 0)
|
||||
{
|
||||
if (num == 0)
|
||||
{
|
||||
throw new ArgumentException("p and q cannot be equal");
|
||||
}
|
||||
BigInteger bigInteger = p;
|
||||
p = q;
|
||||
q = bigInteger;
|
||||
}
|
||||
this.d = new MPInteger(d);
|
||||
this.p = new MPInteger(p);
|
||||
this.q = new MPInteger(q);
|
||||
u = new MPInteger(p.ModInverse(q));
|
||||
expP = d.Remainder(p.Subtract(BigInteger.One));
|
||||
expQ = d.Remainder(q.Subtract(BigInteger.One));
|
||||
crt = q.ModInverse(p);
|
||||
}
|
||||
|
||||
public override byte[] GetEncoded()
|
||||
{
|
||||
try
|
||||
{
|
||||
return base.GetEncoded();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Encode(BcpgOutputStream bcpgOut)
|
||||
{
|
||||
bcpgOut.WriteObjects(d, p, q, u);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
using Org.BouncyCastle.Utilities.IO;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public class S2k : BcpgObject
|
||||
{
|
||||
private const int ExpBias = 6;
|
||||
|
||||
public const int Simple = 0;
|
||||
|
||||
public const int Salted = 1;
|
||||
|
||||
public const int SaltedAndIterated = 3;
|
||||
|
||||
public const int GnuDummyS2K = 101;
|
||||
|
||||
public const int GnuProtectionModeNoPrivateKey = 1;
|
||||
|
||||
public const int GnuProtectionModeDivertToCard = 2;
|
||||
|
||||
internal int type;
|
||||
|
||||
internal HashAlgorithmTag algorithm;
|
||||
|
||||
internal byte[] iv;
|
||||
|
||||
internal int itCount = -1;
|
||||
|
||||
internal int protectionMode = -1;
|
||||
|
||||
public virtual int Type => type;
|
||||
|
||||
public virtual HashAlgorithmTag HashAlgorithm => algorithm;
|
||||
|
||||
public virtual long IterationCount => 16 + (itCount & 0xF) << (itCount >> 4) + 6;
|
||||
|
||||
public virtual int ProtectionMode => protectionMode;
|
||||
|
||||
internal S2k(Stream inStr)
|
||||
{
|
||||
type = inStr.ReadByte();
|
||||
algorithm = (HashAlgorithmTag)inStr.ReadByte();
|
||||
if (type != 101)
|
||||
{
|
||||
if (type != 0)
|
||||
{
|
||||
iv = new byte[8];
|
||||
if (Streams.ReadFully(inStr, iv, 0, iv.Length) < iv.Length)
|
||||
{
|
||||
throw new EndOfStreamException();
|
||||
}
|
||||
if (type == 3)
|
||||
{
|
||||
itCount = inStr.ReadByte();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
inStr.ReadByte();
|
||||
inStr.ReadByte();
|
||||
inStr.ReadByte();
|
||||
protectionMode = inStr.ReadByte();
|
||||
}
|
||||
}
|
||||
|
||||
public S2k(HashAlgorithmTag algorithm)
|
||||
{
|
||||
type = 0;
|
||||
this.algorithm = algorithm;
|
||||
}
|
||||
|
||||
public S2k(HashAlgorithmTag algorithm, byte[] iv)
|
||||
{
|
||||
type = 1;
|
||||
this.algorithm = algorithm;
|
||||
this.iv = iv;
|
||||
}
|
||||
|
||||
public S2k(HashAlgorithmTag algorithm, byte[] iv, int itCount)
|
||||
{
|
||||
type = 3;
|
||||
this.algorithm = algorithm;
|
||||
this.iv = iv;
|
||||
this.itCount = itCount;
|
||||
}
|
||||
|
||||
public virtual byte[] GetIV()
|
||||
{
|
||||
return Arrays.Clone(iv);
|
||||
}
|
||||
|
||||
[Obsolete("Use 'IterationCount' property instead")]
|
||||
public long GetIterationCount()
|
||||
{
|
||||
return IterationCount;
|
||||
}
|
||||
|
||||
public override void Encode(BcpgOutputStream bcpgOut)
|
||||
{
|
||||
bcpgOut.WriteByte((byte)type);
|
||||
bcpgOut.WriteByte((byte)algorithm);
|
||||
if (type != 101)
|
||||
{
|
||||
if (type != 0)
|
||||
{
|
||||
bcpgOut.Write(iv);
|
||||
}
|
||||
if (type == 3)
|
||||
{
|
||||
bcpgOut.WriteByte((byte)itCount);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bcpgOut.WriteByte(71);
|
||||
bcpgOut.WriteByte(78);
|
||||
bcpgOut.WriteByte(85);
|
||||
bcpgOut.WriteByte((byte)protectionMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public class SecretKeyPacket : ContainedPacket
|
||||
{
|
||||
public const int UsageNone = 0;
|
||||
|
||||
public const int UsageChecksum = 255;
|
||||
|
||||
public const int UsageSha1 = 254;
|
||||
|
||||
private PublicKeyPacket pubKeyPacket;
|
||||
|
||||
private readonly byte[] secKeyData;
|
||||
|
||||
private int s2kUsage;
|
||||
|
||||
private SymmetricKeyAlgorithmTag encAlgorithm;
|
||||
|
||||
private S2k s2k;
|
||||
|
||||
private byte[] iv;
|
||||
|
||||
public SymmetricKeyAlgorithmTag EncAlgorithm => encAlgorithm;
|
||||
|
||||
public int S2kUsage => s2kUsage;
|
||||
|
||||
public S2k S2k => s2k;
|
||||
|
||||
public PublicKeyPacket PublicKeyPacket => pubKeyPacket;
|
||||
|
||||
internal SecretKeyPacket(BcpgInputStream bcpgIn)
|
||||
{
|
||||
if (this is SecretSubkeyPacket)
|
||||
{
|
||||
pubKeyPacket = new PublicSubkeyPacket(bcpgIn);
|
||||
}
|
||||
else
|
||||
{
|
||||
pubKeyPacket = new PublicKeyPacket(bcpgIn);
|
||||
}
|
||||
s2kUsage = bcpgIn.ReadByte();
|
||||
if (s2kUsage == 255 || s2kUsage == 254)
|
||||
{
|
||||
encAlgorithm = (SymmetricKeyAlgorithmTag)bcpgIn.ReadByte();
|
||||
s2k = new S2k(bcpgIn);
|
||||
}
|
||||
else
|
||||
{
|
||||
encAlgorithm = (SymmetricKeyAlgorithmTag)s2kUsage;
|
||||
}
|
||||
if ((s2k == null || s2k.Type != 101 || s2k.ProtectionMode != 1) && s2kUsage != 0)
|
||||
{
|
||||
if (encAlgorithm < SymmetricKeyAlgorithmTag.Aes128)
|
||||
{
|
||||
iv = new byte[8];
|
||||
}
|
||||
else
|
||||
{
|
||||
iv = new byte[16];
|
||||
}
|
||||
bcpgIn.ReadFully(iv);
|
||||
}
|
||||
secKeyData = bcpgIn.ReadAll();
|
||||
}
|
||||
|
||||
public SecretKeyPacket(PublicKeyPacket pubKeyPacket, SymmetricKeyAlgorithmTag encAlgorithm, S2k s2k, byte[] iv, byte[] secKeyData)
|
||||
{
|
||||
this.pubKeyPacket = pubKeyPacket;
|
||||
this.encAlgorithm = encAlgorithm;
|
||||
if (encAlgorithm != SymmetricKeyAlgorithmTag.Null)
|
||||
{
|
||||
s2kUsage = 255;
|
||||
}
|
||||
else
|
||||
{
|
||||
s2kUsage = 0;
|
||||
}
|
||||
this.s2k = s2k;
|
||||
this.iv = Arrays.Clone(iv);
|
||||
this.secKeyData = secKeyData;
|
||||
}
|
||||
|
||||
public SecretKeyPacket(PublicKeyPacket pubKeyPacket, SymmetricKeyAlgorithmTag encAlgorithm, int s2kUsage, S2k s2k, byte[] iv, byte[] secKeyData)
|
||||
{
|
||||
this.pubKeyPacket = pubKeyPacket;
|
||||
this.encAlgorithm = encAlgorithm;
|
||||
this.s2kUsage = s2kUsage;
|
||||
this.s2k = s2k;
|
||||
this.iv = Arrays.Clone(iv);
|
||||
this.secKeyData = secKeyData;
|
||||
}
|
||||
|
||||
public byte[] GetIV()
|
||||
{
|
||||
return Arrays.Clone(iv);
|
||||
}
|
||||
|
||||
public byte[] GetSecretKeyData()
|
||||
{
|
||||
return secKeyData;
|
||||
}
|
||||
|
||||
public byte[] GetEncodedContents()
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
BcpgOutputStream bcpgOutputStream = new BcpgOutputStream(memoryStream);
|
||||
bcpgOutputStream.Write(pubKeyPacket.GetEncodedContents());
|
||||
bcpgOutputStream.WriteByte((byte)s2kUsage);
|
||||
if (s2kUsage == 255 || s2kUsage == 254)
|
||||
{
|
||||
bcpgOutputStream.WriteByte((byte)encAlgorithm);
|
||||
bcpgOutputStream.WriteObject(s2k);
|
||||
}
|
||||
if (iv != null)
|
||||
{
|
||||
bcpgOutputStream.Write(iv);
|
||||
}
|
||||
if (secKeyData != null && secKeyData.Length > 0)
|
||||
{
|
||||
bcpgOutputStream.Write(secKeyData);
|
||||
}
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
|
||||
public override void Encode(BcpgOutputStream bcpgOut)
|
||||
{
|
||||
bcpgOut.WritePacket(PacketTag.SecretKey, GetEncodedContents(), oldFormat: true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
namespace Org.BouncyCastle.Bcpg;
|
||||
|
||||
public class SecretSubkeyPacket : SecretKeyPacket
|
||||
{
|
||||
internal SecretSubkeyPacket(BcpgInputStream bcpgIn)
|
||||
: base(bcpgIn)
|
||||
{
|
||||
}
|
||||
|
||||
public SecretSubkeyPacket(PublicKeyPacket pubKeyPacket, SymmetricKeyAlgorithmTag encAlgorithm, S2k s2k, byte[] iv, byte[] secKeyData)
|
||||
: base(pubKeyPacket, encAlgorithm, s2k, iv, secKeyData)
|
||||
{
|
||||
}
|
||||
|
||||
public SecretSubkeyPacket(PublicKeyPacket pubKeyPacket, SymmetricKeyAlgorithmTag encAlgorithm, int s2kUsage, S2k s2k, byte[] iv, byte[] secKeyData)
|
||||
: base(pubKeyPacket, encAlgorithm, s2kUsage, s2k, iv, secKeyData)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Encode(BcpgOutputStream bcpgOut)
|
||||
{
|
||||
bcpgOut.WritePacket(PacketTag.SecretSubkey, GetEncodedContents(), oldFormat: true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Org.BouncyCastle.Bcpg.Sig;
|
||||
|
||||
public class EmbeddedSignature : SignatureSubpacket
|
||||
{
|
||||
public EmbeddedSignature(bool critical, bool isLongLength, byte[] data)
|
||||
: base(SignatureSubpacketTag.EmbeddedSignature, critical, isLongLength, data)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
namespace Org.BouncyCastle.Bcpg.Sig;
|
||||
|
||||
public class Exportable : SignatureSubpacket
|
||||
{
|
||||
private static byte[] BooleanToByteArray(bool val)
|
||||
{
|
||||
byte[] array = new byte[1];
|
||||
if (val)
|
||||
{
|
||||
array[0] = 1;
|
||||
return array;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
public Exportable(bool critical, bool isLongLength, byte[] data)
|
||||
: base(SignatureSubpacketTag.Exportable, critical, isLongLength, data)
|
||||
{
|
||||
}
|
||||
|
||||
public Exportable(bool critical, bool isExportable)
|
||||
: base(SignatureSubpacketTag.Exportable, critical, isLongLength: false, BooleanToByteArray(isExportable))
|
||||
{
|
||||
}
|
||||
|
||||
public bool IsExportable()
|
||||
{
|
||||
return data[0] != 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.Sig;
|
||||
|
||||
public class Features : SignatureSubpacket
|
||||
{
|
||||
public static readonly byte FEATURE_MODIFICATION_DETECTION = 1;
|
||||
|
||||
public bool SupportsModificationDetection => SupportsFeature(FEATURE_MODIFICATION_DETECTION);
|
||||
|
||||
private static byte[] FeatureToByteArray(byte feature)
|
||||
{
|
||||
return new byte[1] { feature };
|
||||
}
|
||||
|
||||
public Features(bool critical, bool isLongLength, byte[] data)
|
||||
: base(SignatureSubpacketTag.Features, critical, isLongLength, data)
|
||||
{
|
||||
}
|
||||
|
||||
public Features(bool critical, byte feature)
|
||||
: base(SignatureSubpacketTag.Features, critical, isLongLength: false, FeatureToByteArray(feature))
|
||||
{
|
||||
}
|
||||
|
||||
public bool SupportsFeature(byte feature)
|
||||
{
|
||||
return Array.IndexOf((Array)data, (object?)feature) >= 0;
|
||||
}
|
||||
|
||||
private void SetSupportsFeature(byte feature, bool support)
|
||||
{
|
||||
if (feature == 0)
|
||||
{
|
||||
throw new ArgumentException("cannot be 0", "feature");
|
||||
}
|
||||
int num = Array.IndexOf((Array)data, (object?)feature);
|
||||
if (num >= 0 != support)
|
||||
{
|
||||
if (support)
|
||||
{
|
||||
data = Arrays.Append(data, feature);
|
||||
return;
|
||||
}
|
||||
byte[] array = new byte[data.Length - 1];
|
||||
Array.Copy(data, 0, array, 0, num);
|
||||
Array.Copy(data, num + 1, array, num, array.Length - num);
|
||||
data = array;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
namespace Org.BouncyCastle.Bcpg.Sig;
|
||||
|
||||
public class IssuerKeyId : SignatureSubpacket
|
||||
{
|
||||
public long KeyId => ((long)(data[0] & 0xFF) << 56) | ((long)(data[1] & 0xFF) << 48) | ((long)(data[2] & 0xFF) << 40) | ((long)(data[3] & 0xFF) << 32) | ((long)(data[4] & 0xFF) << 24) | ((long)(data[5] & 0xFF) << 16) | ((long)(data[6] & 0xFF) << 8) | (long)((ulong)data[7] & 0xFFuL);
|
||||
|
||||
protected static byte[] KeyIdToBytes(long keyId)
|
||||
{
|
||||
return new byte[8]
|
||||
{
|
||||
(byte)(keyId >> 56),
|
||||
(byte)(keyId >> 48),
|
||||
(byte)(keyId >> 40),
|
||||
(byte)(keyId >> 32),
|
||||
(byte)(keyId >> 24),
|
||||
(byte)(keyId >> 16),
|
||||
(byte)(keyId >> 8),
|
||||
(byte)keyId
|
||||
};
|
||||
}
|
||||
|
||||
public IssuerKeyId(bool critical, bool isLongLength, byte[] data)
|
||||
: base(SignatureSubpacketTag.IssuerKeyId, critical, isLongLength, data)
|
||||
{
|
||||
}
|
||||
|
||||
public IssuerKeyId(bool critical, long keyId)
|
||||
: base(SignatureSubpacketTag.IssuerKeyId, critical, isLongLength: false, KeyIdToBytes(keyId))
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
namespace Org.BouncyCastle.Bcpg.Sig;
|
||||
|
||||
public class KeyExpirationTime : SignatureSubpacket
|
||||
{
|
||||
public long Time => ((long)(data[0] & 0xFF) << 24) | ((long)(data[1] & 0xFF) << 16) | ((long)(data[2] & 0xFF) << 8) | (long)((ulong)data[3] & 0xFFuL);
|
||||
|
||||
protected static byte[] TimeToBytes(long t)
|
||||
{
|
||||
return new byte[4]
|
||||
{
|
||||
(byte)(t >> 24),
|
||||
(byte)(t >> 16),
|
||||
(byte)(t >> 8),
|
||||
(byte)t
|
||||
};
|
||||
}
|
||||
|
||||
public KeyExpirationTime(bool critical, bool isLongLength, byte[] data)
|
||||
: base(SignatureSubpacketTag.KeyExpireTime, critical, isLongLength, data)
|
||||
{
|
||||
}
|
||||
|
||||
public KeyExpirationTime(bool critical, long seconds)
|
||||
: base(SignatureSubpacketTag.KeyExpireTime, critical, isLongLength: false, TimeToBytes(seconds))
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.Sig;
|
||||
|
||||
public class KeyFlags : SignatureSubpacket
|
||||
{
|
||||
public const int CertifyOther = 1;
|
||||
|
||||
public const int SignData = 2;
|
||||
|
||||
public const int EncryptComms = 4;
|
||||
|
||||
public const int EncryptStorage = 8;
|
||||
|
||||
public const int Split = 16;
|
||||
|
||||
public const int Authentication = 32;
|
||||
|
||||
public const int Shared = 128;
|
||||
|
||||
public int Flags
|
||||
{
|
||||
get
|
||||
{
|
||||
int num = 0;
|
||||
for (int i = 0; i != data.Length; i++)
|
||||
{
|
||||
num |= (data[i] & 0xFF) << i * 8;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] IntToByteArray(int v)
|
||||
{
|
||||
byte[] array = new byte[4];
|
||||
int num = 0;
|
||||
for (int i = 0; i != 4; i++)
|
||||
{
|
||||
array[i] = (byte)(v >> i * 8);
|
||||
if (array[i] != 0)
|
||||
{
|
||||
num = i;
|
||||
}
|
||||
}
|
||||
byte[] array2 = new byte[num + 1];
|
||||
Array.Copy(array, 0, array2, 0, array2.Length);
|
||||
return array2;
|
||||
}
|
||||
|
||||
public KeyFlags(bool critical, bool isLongLength, byte[] data)
|
||||
: base(SignatureSubpacketTag.KeyFlags, critical, isLongLength, data)
|
||||
{
|
||||
}
|
||||
|
||||
public KeyFlags(bool critical, int flags)
|
||||
: base(SignatureSubpacketTag.KeyFlags, critical, isLongLength: false, IntToByteArray(flags))
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.Sig;
|
||||
|
||||
public class NotationData : SignatureSubpacket
|
||||
{
|
||||
public const int HeaderFlagLength = 4;
|
||||
|
||||
public const int HeaderNameLength = 2;
|
||||
|
||||
public const int HeaderValueLength = 2;
|
||||
|
||||
public bool IsHumanReadable => data[0] == 128;
|
||||
|
||||
public NotationData(bool critical, bool isLongLength, byte[] data)
|
||||
: base(SignatureSubpacketTag.NotationData, critical, isLongLength, data)
|
||||
{
|
||||
}
|
||||
|
||||
public NotationData(bool critical, bool humanReadable, string notationName, string notationValue)
|
||||
: base(SignatureSubpacketTag.NotationData, critical, isLongLength: false, CreateData(humanReadable, notationName, notationValue))
|
||||
{
|
||||
}
|
||||
|
||||
private static byte[] CreateData(bool humanReadable, string notationName, string notationValue)
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
memoryStream.WriteByte((byte)(humanReadable ? 128 : 0));
|
||||
memoryStream.WriteByte(0);
|
||||
memoryStream.WriteByte(0);
|
||||
memoryStream.WriteByte(0);
|
||||
byte[] array = null;
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(notationName);
|
||||
int num = System.Math.Min(bytes.Length, 255);
|
||||
array = Encoding.UTF8.GetBytes(notationValue);
|
||||
int num2 = System.Math.Min(array.Length, 255);
|
||||
memoryStream.WriteByte((byte)(num >> 8));
|
||||
memoryStream.WriteByte((byte)num);
|
||||
memoryStream.WriteByte((byte)(num2 >> 8));
|
||||
memoryStream.WriteByte((byte)num2);
|
||||
memoryStream.Write(bytes, 0, num);
|
||||
memoryStream.Write(array, 0, num2);
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
|
||||
public string GetNotationName()
|
||||
{
|
||||
int count = (data[4] << 8) + data[5];
|
||||
int index = 8;
|
||||
return Encoding.UTF8.GetString(data, index, count);
|
||||
}
|
||||
|
||||
public string GetNotationValue()
|
||||
{
|
||||
int num = (data[4] << 8) + data[5];
|
||||
int count = (data[6] << 8) + data[7];
|
||||
int index = 8 + num;
|
||||
return Encoding.UTF8.GetString(data, index, count);
|
||||
}
|
||||
|
||||
public byte[] GetNotationValueBytes()
|
||||
{
|
||||
int num = (data[4] << 8) + data[5];
|
||||
int num2 = (data[6] << 8) + data[7];
|
||||
int sourceIndex = 8 + num;
|
||||
byte[] array = new byte[num2];
|
||||
Array.Copy(data, sourceIndex, array, 0, num2);
|
||||
return array;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
namespace Org.BouncyCastle.Bcpg.Sig;
|
||||
|
||||
public class PreferredAlgorithms : SignatureSubpacket
|
||||
{
|
||||
private static byte[] IntToByteArray(int[] v)
|
||||
{
|
||||
byte[] array = new byte[v.Length];
|
||||
for (int i = 0; i != v.Length; i++)
|
||||
{
|
||||
array[i] = (byte)v[i];
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
public PreferredAlgorithms(SignatureSubpacketTag type, bool critical, bool isLongLength, byte[] data)
|
||||
: base(type, critical, isLongLength, data)
|
||||
{
|
||||
}
|
||||
|
||||
public PreferredAlgorithms(SignatureSubpacketTag type, bool critical, int[] preferences)
|
||||
: base(type, critical, isLongLength: false, IntToByteArray(preferences))
|
||||
{
|
||||
}
|
||||
|
||||
public int[] GetPreferences()
|
||||
{
|
||||
int[] array = new int[data.Length];
|
||||
for (int i = 0; i != array.Length; i++)
|
||||
{
|
||||
array[i] = data[i] & 0xFF;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
namespace Org.BouncyCastle.Bcpg.Sig;
|
||||
|
||||
public class PrimaryUserId : SignatureSubpacket
|
||||
{
|
||||
private static byte[] BooleanToByteArray(bool val)
|
||||
{
|
||||
byte[] array = new byte[1];
|
||||
if (val)
|
||||
{
|
||||
array[0] = 1;
|
||||
return array;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
public PrimaryUserId(bool critical, bool isLongLength, byte[] data)
|
||||
: base(SignatureSubpacketTag.PrimaryUserId, critical, isLongLength, data)
|
||||
{
|
||||
}
|
||||
|
||||
public PrimaryUserId(bool critical, bool isPrimaryUserId)
|
||||
: base(SignatureSubpacketTag.PrimaryUserId, critical, isLongLength: false, BooleanToByteArray(isPrimaryUserId))
|
||||
{
|
||||
}
|
||||
|
||||
public bool IsPrimaryUserId()
|
||||
{
|
||||
return data[0] != 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
namespace Org.BouncyCastle.Bcpg.Sig;
|
||||
|
||||
public class Revocable : SignatureSubpacket
|
||||
{
|
||||
private static byte[] BooleanToByteArray(bool value)
|
||||
{
|
||||
byte[] array = new byte[1];
|
||||
if (value)
|
||||
{
|
||||
array[0] = 1;
|
||||
return array;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
public Revocable(bool critical, bool isLongLength, byte[] data)
|
||||
: base(SignatureSubpacketTag.Revocable, critical, isLongLength, data)
|
||||
{
|
||||
}
|
||||
|
||||
public Revocable(bool critical, bool isRevocable)
|
||||
: base(SignatureSubpacketTag.Revocable, critical, isLongLength: false, BooleanToByteArray(isRevocable))
|
||||
{
|
||||
}
|
||||
|
||||
public bool IsRevocable()
|
||||
{
|
||||
return data[0] != 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using Org.BouncyCastle.Utilities.Date;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.Sig;
|
||||
|
||||
public class SignatureCreationTime : SignatureSubpacket
|
||||
{
|
||||
protected static byte[] TimeToBytes(DateTime time)
|
||||
{
|
||||
long num = DateTimeUtilities.DateTimeToUnixMs(time) / 1000;
|
||||
return new byte[4]
|
||||
{
|
||||
(byte)(num >> 24),
|
||||
(byte)(num >> 16),
|
||||
(byte)(num >> 8),
|
||||
(byte)num
|
||||
};
|
||||
}
|
||||
|
||||
public SignatureCreationTime(bool critical, bool isLongLength, byte[] data)
|
||||
: base(SignatureSubpacketTag.CreationTime, critical, isLongLength, data)
|
||||
{
|
||||
}
|
||||
|
||||
public SignatureCreationTime(bool critical, DateTime date)
|
||||
: base(SignatureSubpacketTag.CreationTime, critical, isLongLength: false, TimeToBytes(date))
|
||||
{
|
||||
}
|
||||
|
||||
public DateTime GetTime()
|
||||
{
|
||||
long num = (uint)((data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]);
|
||||
return DateTimeUtilities.UnixMsToDateTime(num * 1000);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
namespace Org.BouncyCastle.Bcpg.Sig;
|
||||
|
||||
public class SignatureExpirationTime : SignatureSubpacket
|
||||
{
|
||||
public long Time => ((long)(data[0] & 0xFF) << 24) | ((long)(data[1] & 0xFF) << 16) | ((long)(data[2] & 0xFF) << 8) | (long)((ulong)data[3] & 0xFFuL);
|
||||
|
||||
protected static byte[] TimeToBytes(long t)
|
||||
{
|
||||
return new byte[4]
|
||||
{
|
||||
(byte)(t >> 24),
|
||||
(byte)(t >> 16),
|
||||
(byte)(t >> 8),
|
||||
(byte)t
|
||||
};
|
||||
}
|
||||
|
||||
public SignatureExpirationTime(bool critical, bool isLongLength, byte[] data)
|
||||
: base(SignatureSubpacketTag.ExpireTime, critical, isLongLength, data)
|
||||
{
|
||||
}
|
||||
|
||||
public SignatureExpirationTime(bool critical, long seconds)
|
||||
: base(SignatureSubpacketTag.ExpireTime, critical, isLongLength: false, TimeToBytes(seconds))
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
namespace Org.BouncyCastle.Bcpg.Sig;
|
||||
|
||||
public class SignerUserId : SignatureSubpacket
|
||||
{
|
||||
private static byte[] UserIdToBytes(string id)
|
||||
{
|
||||
byte[] array = new byte[id.Length];
|
||||
for (int i = 0; i != id.Length; i++)
|
||||
{
|
||||
array[i] = (byte)id[i];
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
public SignerUserId(bool critical, bool isLongLength, byte[] data)
|
||||
: base(SignatureSubpacketTag.SignerUserId, critical, isLongLength, data)
|
||||
{
|
||||
}
|
||||
|
||||
public SignerUserId(bool critical, string userId)
|
||||
: base(SignatureSubpacketTag.SignerUserId, critical, isLongLength: false, UserIdToBytes(userId))
|
||||
{
|
||||
}
|
||||
|
||||
public string GetId()
|
||||
{
|
||||
char[] array = new char[data.Length];
|
||||
for (int i = 0; i != array.Length; i++)
|
||||
{
|
||||
array[i] = (char)(data[i] & 0xFF);
|
||||
}
|
||||
return new string(array);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
namespace Org.BouncyCastle.Bcpg.Sig;
|
||||
|
||||
public class TrustSignature : SignatureSubpacket
|
||||
{
|
||||
public int Depth => data[0] & 0xFF;
|
||||
|
||||
public int TrustAmount => data[1] & 0xFF;
|
||||
|
||||
private static byte[] IntToByteArray(int v1, int v2)
|
||||
{
|
||||
return new byte[2]
|
||||
{
|
||||
(byte)v1,
|
||||
(byte)v2
|
||||
};
|
||||
}
|
||||
|
||||
public TrustSignature(bool critical, bool isLongLength, byte[] data)
|
||||
: base(SignatureSubpacketTag.TrustSig, critical, isLongLength, data)
|
||||
{
|
||||
}
|
||||
|
||||
public TrustSignature(bool critical, int depth, int trustAmount)
|
||||
: base(SignatureSubpacketTag.TrustSig, critical, isLongLength: false, IntToByteArray(depth, trustAmount))
|
||||
{
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user