Skip to content

Commit 6441531

Browse files
committed
Migrate to new S Expression code from bcgit/bc-csharp#282
1 parent 51cc8a6 commit 6441531

File tree

4 files changed

+473
-194
lines changed

4 files changed

+473
-194
lines changed

src/Org/BouncyCastle/Bcpg/OpenPgp/PgpSecretKey.cs

+147-92
Original file line numberDiff line numberDiff line change
@@ -1113,58 +1113,6 @@ public static PgpSecretKey ParseSecretKeyFromSExprRaw(Stream inputStream, byte[]
11131113
return DoParseSecretKeyFromSExpr(inputStream, rawPassPhrase, false, pubKey);
11141114
}
11151115

1116-
internal static PgpSecretKey DoParseSecretKeyFromSExpr(Stream inputStream, byte[] rawPassPhrase, bool clearPassPhrase, PgpPublicKey pubKey)
1117-
{
1118-
SXprUtilities.SkipOpenParenthesis(inputStream);
1119-
1120-
string type = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
1121-
if (type.Equals("protected-private-key"))
1122-
{
1123-
SXprUtilities.SkipOpenParenthesis(inputStream);
1124-
1125-
string curveName;
1126-
1127-
string keyType = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
1128-
if (keyType.Equals("ecc"))
1129-
{
1130-
SXprUtilities.SkipOpenParenthesis(inputStream);
1131-
1132-
string curveID = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
1133-
curveName = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
1134-
1135-
SXprUtilities.SkipCloseParenthesis(inputStream);
1136-
}
1137-
else
1138-
{
1139-
throw new PgpException("no curve details found");
1140-
}
1141-
1142-
byte[] qVal;
1143-
1144-
SXprUtilities.SkipOpenParenthesis(inputStream);
1145-
1146-
type = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
1147-
if (type.Equals("q"))
1148-
{
1149-
qVal = SXprUtilities.ReadBytes(inputStream, inputStream.ReadByte());
1150-
}
1151-
else
1152-
{
1153-
throw new PgpException("no q value found");
1154-
}
1155-
1156-
SXprUtilities.SkipCloseParenthesis(inputStream);
1157-
1158-
byte[] dValue = GetDValue(inputStream, rawPassPhrase, clearPassPhrase, curveName);
1159-
// TODO: check SHA-1 hash.
1160-
1161-
return new PgpSecretKey(new SecretKeyPacket(pubKey.PublicKeyPacket, SymmetricKeyAlgorithmTag.Null, null, null,
1162-
new ECSecretBcpgKey(new MPInteger(dValue)).GetEncoded()), pubKey);
1163-
}
1164-
1165-
throw new PgpException("unknown key type found");
1166-
}
1167-
11681116
/// <summary>
11691117
/// Parse a secret key from one of the GPG S expression keys.
11701118
/// </summary>
@@ -1174,7 +1122,7 @@ internal static PgpSecretKey DoParseSecretKeyFromSExpr(Stream inputStream, byte[
11741122
/// </remarks>
11751123
public static PgpSecretKey ParseSecretKeyFromSExpr(Stream inputStream, char[] passPhrase)
11761124
{
1177-
return DoParseSecretKeyFromSExpr(inputStream, PgpUtilities.EncodePassPhrase(passPhrase, false), true);
1125+
return DoParseSecretKeyFromSExpr(inputStream, PgpUtilities.EncodePassPhrase(passPhrase, false), true, null);
11781126
}
11791127

11801128
/// <summary>
@@ -1185,7 +1133,7 @@ public static PgpSecretKey ParseSecretKeyFromSExpr(Stream inputStream, char[] pa
11851133
/// </remarks>
11861134
public static PgpSecretKey ParseSecretKeyFromSExprUtf8(Stream inputStream, char[] passPhrase)
11871135
{
1188-
return DoParseSecretKeyFromSExpr(inputStream, PgpUtilities.EncodePassPhrase(passPhrase, true), true);
1136+
return DoParseSecretKeyFromSExpr(inputStream, PgpUtilities.EncodePassPhrase(passPhrase, true), true, null);
11891137
}
11901138

11911139
/// <summary>
@@ -1196,31 +1144,33 @@ public static PgpSecretKey ParseSecretKeyFromSExprUtf8(Stream inputStream, char[
11961144
/// </remarks>
11971145
public static PgpSecretKey ParseSecretKeyFromSExprRaw(Stream inputStream, byte[] rawPassPhrase)
11981146
{
1199-
return DoParseSecretKeyFromSExpr(inputStream, rawPassPhrase, false);
1147+
return DoParseSecretKeyFromSExpr(inputStream, rawPassPhrase, false, null);
12001148
}
12011149

12021150
/// <summary>
12031151
/// Parse a secret key from one of the GPG S expression keys.
12041152
/// </summary>
1205-
internal static PgpSecretKey DoParseSecretKeyFromSExpr(Stream inputStream, byte[] rawPassPhrase, bool clearPassPhrase)
1153+
internal static PgpSecretKey DoParseSecretKeyFromSExpr(Stream inputStream, byte[] rawPassPhrase, bool clearPassPhrase, PgpPublicKey pubKey)
12061154
{
1207-
SXprUtilities.SkipOpenParenthesis(inputStream);
1155+
SXprReader reader = new SXprReader(inputStream);
12081156

1209-
string type = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
1157+
reader.SkipOpenParenthesis();
1158+
1159+
string type = reader.ReadString();
12101160
if (type.Equals("protected-private-key"))
12111161
{
1212-
SXprUtilities.SkipOpenParenthesis(inputStream);
1162+
reader.SkipOpenParenthesis();
12131163

12141164
string curveName;
12151165
Oid curveOid;
12161166

1217-
string keyType = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
1167+
string keyType = reader.ReadString();
12181168
if (keyType.Equals("ecc"))
12191169
{
1220-
SXprUtilities.SkipOpenParenthesis(inputStream);
1170+
reader.SkipOpenParenthesis();
12211171

1222-
string curveID = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
1223-
curveName = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
1172+
string curveID = reader.ReadString();
1173+
curveName = reader.ReadString();
12241174

12251175
switch (curveName)
12261176
{
@@ -1230,92 +1180,197 @@ internal static PgpSecretKey DoParseSecretKeyFromSExpr(Stream inputStream, byte[
12301180
case "brainpoolP256r1": curveOid = new Oid("1.3.36.3.3.2.8.1.1.7"); break;
12311181
case "brainpoolP384r1": curveOid = new Oid("1.3.36.3.3.2.8.1.1.11"); break;
12321182
case "brainpoolP512r1": curveOid = new Oid("1.3.36.3.3.2.8.1.1.13"); break;
1233-
// FIXME: curve25519
1183+
case "Curve25519": curveOid = new Oid("1.3.6.1.4.1.3029.1.5.1"); break;
1184+
case "Ed25519": curveOid = new Oid("1.3.6.1.4.1.11591.15.1"); break;
12341185
default:
12351186
throw new PgpException("unknown curve algorithm");
12361187
}
12371188

1238-
SXprUtilities.SkipCloseParenthesis(inputStream);
1189+
reader.SkipCloseParenthesis();
12391190
}
12401191
else
12411192
{
12421193
throw new PgpException("no curve details found");
12431194
}
12441195

12451196
byte[] qVal;
1197+
string flags = null;
12461198

1247-
SXprUtilities.SkipOpenParenthesis(inputStream);
1199+
reader.SkipOpenParenthesis();
12481200

1249-
type = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
1201+
type = reader.ReadString();
1202+
if (type == "flags")
1203+
{
1204+
// Skip over flags
1205+
flags = reader.ReadString();
1206+
reader.SkipCloseParenthesis();
1207+
reader.SkipOpenParenthesis();
1208+
type = reader.ReadString();
1209+
}
12501210
if (type.Equals("q"))
12511211
{
1252-
qVal = SXprUtilities.ReadBytes(inputStream, inputStream.ReadByte());
1212+
qVal = reader.ReadBytes();
12531213
}
12541214
else
12551215
{
12561216
throw new PgpException("no q value found");
12571217
}
12581218

1259-
PublicKeyPacket pubPacket = new PublicKeyPacket(PublicKeyAlgorithmTag.ECDsa, DateTime.UtcNow,
1260-
new ECDsaPublicBcpgKey(curveOid, new MPInteger(qVal)));
1219+
if (pubKey == null)
1220+
{
1221+
PublicKeyPacket pubPacket = new PublicKeyPacket(
1222+
flags == "eddsa" ? PublicKeyAlgorithmTag.EdDsa : PublicKeyAlgorithmTag.ECDsa, DateTime.UtcNow,
1223+
new ECDsaPublicBcpgKey(curveOid, new MPInteger(qVal)));
1224+
pubKey = new PgpPublicKey(pubPacket);
1225+
}
12611226

1262-
SXprUtilities.SkipCloseParenthesis(inputStream);
1227+
reader.SkipCloseParenthesis();
12631228

1264-
byte[] dValue = GetDValue(inputStream, rawPassPhrase, clearPassPhrase, curveName);
1265-
// TODO: check SHA-1 hash.
1229+
byte[] dValue = GetDValue(reader, pubKey.PublicKeyPacket, rawPassPhrase, clearPassPhrase, curveName);
12661230

1267-
return new PgpSecretKey(new SecretKeyPacket(pubPacket, SymmetricKeyAlgorithmTag.Null, null, null,
1268-
new ECSecretBcpgKey(new MPInteger(dValue)).GetEncoded()), new PgpPublicKey(pubPacket));
1231+
return new PgpSecretKey(new SecretKeyPacket(pubKey.PublicKeyPacket, SymmetricKeyAlgorithmTag.Null, null, null,
1232+
new ECSecretBcpgKey(new MPInteger(dValue)).GetEncoded()), pubKey);
12691233
}
12701234

12711235
throw new PgpException("unknown key type found");
12721236
}
12731237

1274-
private static byte[] GetDValue(Stream inputStream, byte[] rawPassPhrase, bool clearPassPhrase, string curveName)
1238+
private static void WriteSExprPublicKey(SXprWriter writer, PublicKeyPacket pubPacket, string curveName, string protectedAt)
1239+
{
1240+
writer.StartList();
1241+
switch (pubPacket.Algorithm)
1242+
{
1243+
case PublicKeyAlgorithmTag.ECDsa:
1244+
case PublicKeyAlgorithmTag.EdDsa:
1245+
writer.WriteString("ecc");
1246+
writer.StartList();
1247+
writer.WriteString("curve");
1248+
writer.WriteString(curveName);
1249+
writer.EndList();
1250+
if (pubPacket.Algorithm == PublicKeyAlgorithmTag.EdDsa)
1251+
{
1252+
writer.StartList();
1253+
writer.WriteString("flags");
1254+
writer.WriteString("eddsa");
1255+
writer.EndList();
1256+
}
1257+
writer.StartList();
1258+
writer.WriteString("q");
1259+
writer.WriteBytes(((ECDsaPublicBcpgKey)pubPacket.Key).EncodedPoint.Value);
1260+
writer.EndList();
1261+
break;
1262+
1263+
case PublicKeyAlgorithmTag.RsaEncrypt:
1264+
case PublicKeyAlgorithmTag.RsaSign:
1265+
case PublicKeyAlgorithmTag.RsaGeneral:
1266+
RsaPublicBcpgKey rsaK = (RsaPublicBcpgKey)pubPacket.Key;
1267+
writer.WriteString("rsa");
1268+
writer.StartList();
1269+
writer.WriteString("n");
1270+
writer.WriteBytes(rsaK.Modulus.Value);
1271+
writer.EndList();
1272+
writer.StartList();
1273+
writer.WriteString("e");
1274+
writer.WriteBytes(rsaK.PublicExponent.Value);
1275+
writer.EndList();
1276+
break;
1277+
1278+
// TODO: DSA, etc.
1279+
default:
1280+
throw new PgpException("unsupported algorithm in S expression");
1281+
}
1282+
1283+
if (protectedAt != null)
1284+
{
1285+
writer.StartList();
1286+
writer.WriteString("protected-at");
1287+
writer.WriteString(protectedAt);
1288+
writer.EndList();
1289+
}
1290+
writer.EndList();
1291+
}
1292+
1293+
private static byte[] GetDValue(SXprReader reader, PublicKeyPacket publicKey, byte[] rawPassPhrase, bool clearPassPhrase, string curveName)
12751294
{
12761295
string type;
1277-
SXprUtilities.SkipOpenParenthesis(inputStream);
1296+
reader.SkipOpenParenthesis();
12781297

12791298
string protection;
1299+
string protectedAt = null;
12801300
S2k s2k;
12811301
byte[] iv;
12821302
byte[] secKeyData;
12831303

1284-
type = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
1304+
type = reader.ReadString();
12851305
if (type.Equals("protected"))
12861306
{
1287-
protection = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
1307+
protection = reader.ReadString();
1308+
1309+
reader.SkipOpenParenthesis();
1310+
1311+
s2k = reader.ParseS2k();
1312+
1313+
iv = reader.ReadBytes();
12881314

1289-
SXprUtilities.SkipOpenParenthesis(inputStream);
1315+
reader.SkipCloseParenthesis();
12901316

1291-
s2k = SXprUtilities.ParseS2k(inputStream);
1317+
secKeyData = reader.ReadBytes();
12921318

1293-
iv = SXprUtilities.ReadBytes(inputStream, inputStream.ReadByte());
1319+
reader.SkipCloseParenthesis();
12941320

1295-
SXprUtilities.SkipCloseParenthesis(inputStream);
1321+
reader.SkipOpenParenthesis();
12961322

1297-
secKeyData = SXprUtilities.ReadBytes(inputStream, inputStream.ReadByte());
1323+
if (reader.ReadString().Equals("protected-at"))
1324+
{
1325+
protectedAt = reader.ReadString();
1326+
}
12981327
}
12991328
else
13001329
{
13011330
throw new PgpException("protected block not found");
13021331
}
13031332

1304-
// TODO: recognise other algorithms
1305-
byte[] key = PgpUtilities.DoMakeKeyFromPassPhrase(SymmetricKeyAlgorithmTag.Aes128, s2k, rawPassPhrase, clearPassPhrase);
1333+
byte[] data;
1334+
byte[] key;
1335+
1336+
switch (protection)
1337+
{
1338+
case "openpgp-s2k3-sha1-aes256-cbc":
1339+
case "openpgp-s2k3-sha1-aes-cbc":
1340+
SymmetricKeyAlgorithmTag symmAlg =
1341+
protection.Equals("openpgp-s2k3-sha1-aes256-cbc") ? SymmetricKeyAlgorithmTag.Aes256 : SymmetricKeyAlgorithmTag.Aes128;
1342+
key = PgpUtilities.DoMakeKeyFromPassPhrase(symmAlg, s2k, rawPassPhrase, clearPassPhrase);
1343+
data = RecoverKeyData(symmAlg, CipherMode.CBC, key, iv, secKeyData, 0, secKeyData.Length);
1344+
// TODO: check SHA-1 hash.
1345+
break;
13061346

1307-
byte[] data = RecoverKeyData(SymmetricKeyAlgorithmTag.Aes128, CipherMode.CBC, key, iv, secKeyData, 0, secKeyData.Length);
1347+
case "openpgp-s2k3-ocb-aes":
1348+
MemoryStream aad = new MemoryStream();
1349+
WriteSExprPublicKey(new SXprWriter(aad), publicKey, curveName, protectedAt);
1350+
key = PgpUtilities.DoMakeKeyFromPassPhrase(SymmetricKeyAlgorithmTag.Aes128, s2k, rawPassPhrase, clearPassPhrase);
1351+
/*IBufferedCipher c = CipherUtilities.GetCipher("AES/OCB");
1352+
c.Init(false, new AeadParameters(key, 128, iv, aad.ToArray()));
1353+
data = c.DoFinal(secKeyData, 0, secKeyData.Length);*/
1354+
// TODO: AES/OCB support
1355+
throw new NotImplementedException();
1356+
break;
1357+
1358+
case "openpgp-native":
1359+
default:
1360+
throw new PgpException(protection + " key format is not supported yet");
1361+
}
13081362

13091363
//
13101364
// parse the secret key S-expr
13111365
//
13121366
Stream keyIn = new MemoryStream(data, false);
13131367

1314-
SXprUtilities.SkipOpenParenthesis(keyIn);
1315-
SXprUtilities.SkipOpenParenthesis(keyIn);
1316-
SXprUtilities.SkipOpenParenthesis(keyIn);
1317-
String name = SXprUtilities.ReadString(keyIn, keyIn.ReadByte());
1318-
return SXprUtilities.ReadBytes(keyIn, keyIn.ReadByte());
1368+
reader = new SXprReader(keyIn);
1369+
reader.SkipOpenParenthesis();
1370+
reader.SkipOpenParenthesis();
1371+
reader.SkipOpenParenthesis();
1372+
String name = reader.ReadString();
1373+
return reader.ReadBytes();
13191374
}
13201375
}
13211376
}

0 commit comments

Comments
 (0)