1
1
using System ;
2
2
using System . Collections ;
3
+ using System . Diagnostics ;
3
4
using System . IO ;
5
+ using Org . BouncyCastle . Asn1 ;
4
6
using Org . BouncyCastle . Asn1 . Misc ;
5
7
using Org . BouncyCastle . Asn1 . X9 ;
6
8
using Org . BouncyCastle . Crypto ;
9
+ using Org . BouncyCastle . Crypto . EC ;
7
10
using Org . BouncyCastle . Crypto . Generators ;
8
11
using Org . BouncyCastle . Crypto . Parameters ;
9
12
using Org . BouncyCastle . Math ;
@@ -57,6 +60,10 @@ internal PgpSecretKey(
57
60
ECPrivateKeyParameters ecK = ( ECPrivateKeyParameters ) privKey . Key ;
58
61
secKey = new ECSecretBcpgKey ( ecK . D ) ;
59
62
break ;
63
+ case PublicKeyAlgorithmTag . EdDsa :
64
+ Ed25519PrivateKeyParameters edK = ( Ed25519PrivateKeyParameters ) privKey . Key ;
65
+ secKey = new ECSecretBcpgKey ( new BigInteger ( 1 , edK . GetEncoded ( ) ) ) ;
66
+ break ;
60
67
case PublicKeyAlgorithmTag . ElGamalEncrypt :
61
68
case PublicKeyAlgorithmTag . ElGamalGeneral :
62
69
ElGamalPrivateKeyParameters esK = ( ElGamalPrivateKeyParameters ) privKey . Key ;
@@ -1111,24 +1118,26 @@ public static PgpSecretKey ParseSecretKeyFromSExprRaw(Stream inputStream, byte[]
1111
1118
1112
1119
internal static PgpSecretKey DoParseSecretKeyFromSExpr ( Stream inputStream , byte [ ] rawPassPhrase , bool clearPassPhrase , PgpPublicKey pubKey )
1113
1120
{
1114
- SXprUtilities . SkipOpenParenthesis ( inputStream ) ;
1121
+ SXprUtilities reader = new SXprUtilities ( inputStream ) ;
1122
+
1123
+ reader . SkipOpenParenthesis ( ) ;
1115
1124
1116
- string type = SXprUtilities . ReadString ( inputStream , inputStream . ReadByte ( ) ) ;
1125
+ string type = reader . ReadString ( ) ;
1117
1126
if ( type . Equals ( "protected-private-key" ) )
1118
1127
{
1119
- SXprUtilities . SkipOpenParenthesis ( inputStream ) ;
1128
+ reader . SkipOpenParenthesis ( ) ;
1120
1129
1121
1130
string curveName ;
1122
1131
1123
- string keyType = SXprUtilities . ReadString ( inputStream , inputStream . ReadByte ( ) ) ;
1132
+ string keyType = reader . ReadString ( ) ;
1124
1133
if ( keyType . Equals ( "ecc" ) )
1125
1134
{
1126
- SXprUtilities . SkipOpenParenthesis ( inputStream ) ;
1135
+ reader . SkipOpenParenthesis ( ) ;
1127
1136
1128
- string curveID = SXprUtilities . ReadString ( inputStream , inputStream . ReadByte ( ) ) ;
1129
- curveName = SXprUtilities . ReadString ( inputStream , inputStream . ReadByte ( ) ) ;
1137
+ string curveID = reader . ReadString ( ) ;
1138
+ curveName = reader . ReadString ( ) ;
1130
1139
1131
- SXprUtilities . SkipCloseParenthesis ( inputStream ) ;
1140
+ reader . SkipCloseParenthesis ( ) ;
1132
1141
}
1133
1142
else
1134
1143
{
@@ -1137,21 +1146,21 @@ internal static PgpSecretKey DoParseSecretKeyFromSExpr(Stream inputStream, byte[
1137
1146
1138
1147
byte [ ] qVal ;
1139
1148
1140
- SXprUtilities . SkipOpenParenthesis ( inputStream ) ;
1149
+ reader . SkipOpenParenthesis ( ) ;
1141
1150
1142
- type = SXprUtilities . ReadString ( inputStream , inputStream . ReadByte ( ) ) ;
1151
+ type = reader . ReadString ( ) ;
1143
1152
if ( type . Equals ( "q" ) )
1144
1153
{
1145
- qVal = SXprUtilities . ReadBytes ( inputStream , inputStream . ReadByte ( ) ) ;
1154
+ qVal = reader . ReadBytes ( ) ;
1146
1155
}
1147
1156
else
1148
1157
{
1149
1158
throw new PgpException ( "no q value found" ) ;
1150
1159
}
1151
1160
1152
- SXprUtilities . SkipCloseParenthesis ( inputStream ) ;
1161
+ reader . SkipCloseParenthesis ( ) ;
1153
1162
1154
- byte [ ] dValue = GetDValue ( inputStream , rawPassPhrase , clearPassPhrase , curveName ) ;
1163
+ byte [ ] dValue = GetDValue ( reader , rawPassPhrase , clearPassPhrase , curveName ) ;
1155
1164
// TODO: check SHA-1 hash.
1156
1165
1157
1166
return new PgpSecretKey ( new SecretKeyPacket ( pubKey . PublicKeyPacket , SymmetricKeyAlgorithmTag . Null , null , null ,
@@ -1170,7 +1179,7 @@ internal static PgpSecretKey DoParseSecretKeyFromSExpr(Stream inputStream, byte[
1170
1179
/// </remarks>
1171
1180
public static PgpSecretKey ParseSecretKeyFromSExpr ( Stream inputStream , char [ ] passPhrase )
1172
1181
{
1173
- return DoParseSecretKeyFromSExpr ( inputStream , PgpUtilities . EncodePassPhrase ( passPhrase , false ) , true ) ;
1182
+ return DoParseSecretKeyFromSExpr ( new SXprUtilities ( inputStream ) , PgpUtilities . EncodePassPhrase ( passPhrase , false ) , true ) ;
1174
1183
}
1175
1184
1176
1185
/// <summary>
@@ -1181,7 +1190,7 @@ public static PgpSecretKey ParseSecretKeyFromSExpr(Stream inputStream, char[] pa
1181
1190
/// </remarks>
1182
1191
public static PgpSecretKey ParseSecretKeyFromSExprUtf8 ( Stream inputStream , char [ ] passPhrase )
1183
1192
{
1184
- return DoParseSecretKeyFromSExpr ( inputStream , PgpUtilities . EncodePassPhrase ( passPhrase , true ) , true ) ;
1193
+ return DoParseSecretKeyFromSExpr ( new SXprUtilities ( inputStream ) , PgpUtilities . EncodePassPhrase ( passPhrase , true ) , true ) ;
1185
1194
}
1186
1195
1187
1196
/// <summary>
@@ -1192,63 +1201,84 @@ public static PgpSecretKey ParseSecretKeyFromSExprUtf8(Stream inputStream, char[
1192
1201
/// </remarks>
1193
1202
public static PgpSecretKey ParseSecretKeyFromSExprRaw ( Stream inputStream , byte [ ] rawPassPhrase )
1194
1203
{
1195
- return DoParseSecretKeyFromSExpr ( inputStream , rawPassPhrase , false ) ;
1204
+ return DoParseSecretKeyFromSExpr ( new SXprUtilities ( inputStream ) , rawPassPhrase , false ) ;
1196
1205
}
1197
1206
1198
1207
/// <summary>
1199
1208
/// Parse a secret key from one of the GPG S expression keys.
1200
1209
/// </summary>
1201
- internal static PgpSecretKey DoParseSecretKeyFromSExpr ( Stream inputStream , byte [ ] rawPassPhrase , bool clearPassPhrase )
1210
+ internal static PgpSecretKey DoParseSecretKeyFromSExpr ( SXprUtilities reader , byte [ ] rawPassPhrase , bool clearPassPhrase )
1202
1211
{
1203
- SXprUtilities . SkipOpenParenthesis ( inputStream ) ;
1212
+ reader . SkipOpenParenthesis ( ) ;
1204
1213
1205
- string type = SXprUtilities . ReadString ( inputStream , inputStream . ReadByte ( ) ) ;
1214
+ string type = reader . ReadString ( ) ;
1206
1215
if ( type . Equals ( "protected-private-key" ) )
1207
1216
{
1208
- SXprUtilities . SkipOpenParenthesis ( inputStream ) ;
1217
+ reader . SkipOpenParenthesis ( ) ;
1209
1218
1210
1219
string curveName ;
1220
+ DerObjectIdentifier curveOid ;
1211
1221
1212
- string keyType = SXprUtilities . ReadString ( inputStream , inputStream . ReadByte ( ) ) ;
1222
+ string keyType = reader . ReadString ( ) ;
1213
1223
if ( keyType . Equals ( "ecc" ) )
1214
1224
{
1215
- SXprUtilities . SkipOpenParenthesis ( inputStream ) ;
1225
+ reader . SkipOpenParenthesis ( ) ;
1216
1226
1217
- string curveID = SXprUtilities . ReadString ( inputStream , inputStream . ReadByte ( ) ) ;
1218
- curveName = SXprUtilities . ReadString ( inputStream , inputStream . ReadByte ( ) ) ;
1227
+ string curveID = reader . ReadString ( ) ;
1228
+ curveName = reader . ReadString ( ) ;
1219
1229
1220
1230
if ( Platform . StartsWith ( curveName , "NIST " ) )
1221
1231
{
1222
1232
curveName = curveName . Substring ( "NIST " . Length ) ;
1223
1233
}
1224
1234
1225
- SXprUtilities . SkipCloseParenthesis ( inputStream ) ;
1235
+ curveOid = ECNamedCurveTable . GetOid ( curveName ) ;
1236
+ if ( curveOid == null )
1237
+ {
1238
+ curveOid = CustomNamedCurves . GetOid ( curveName ) ;
1239
+ }
1240
+ if ( curveOid == null )
1241
+ {
1242
+ throw new PgpException ( "unknown curve" ) ;
1243
+ }
1244
+
1245
+ reader . SkipCloseParenthesis ( ) ;
1226
1246
}
1227
1247
else
1228
1248
{
1229
1249
throw new PgpException ( "no curve details found" ) ;
1230
1250
}
1231
1251
1232
1252
byte [ ] qVal ;
1253
+ string flags = null ;
1233
1254
1234
- SXprUtilities . SkipOpenParenthesis ( inputStream ) ;
1255
+ reader . SkipOpenParenthesis ( ) ;
1235
1256
1236
- type = SXprUtilities . ReadString ( inputStream , inputStream . ReadByte ( ) ) ;
1257
+ type = reader . ReadString ( ) ;
1258
+ if ( type == "flags" )
1259
+ {
1260
+ // Skip over flags
1261
+ flags = reader . ReadString ( ) ;
1262
+ reader . SkipCloseParenthesis ( ) ;
1263
+ reader . SkipOpenParenthesis ( ) ;
1264
+ type = reader . ReadString ( ) ;
1265
+ }
1237
1266
if ( type . Equals ( "q" ) )
1238
1267
{
1239
- qVal = SXprUtilities . ReadBytes ( inputStream , inputStream . ReadByte ( ) ) ;
1268
+ qVal = reader . ReadBytes ( ) ;
1240
1269
}
1241
1270
else
1242
1271
{
1243
1272
throw new PgpException ( "no q value found" ) ;
1244
1273
}
1245
1274
1246
- PublicKeyPacket pubPacket = new PublicKeyPacket ( PublicKeyAlgorithmTag . ECDsa , DateTime . UtcNow ,
1247
- new ECDsaPublicBcpgKey ( ECNamedCurveTable . GetOid ( curveName ) , new BigInteger ( 1 , qVal ) ) ) ;
1275
+ PublicKeyPacket pubPacket = new PublicKeyPacket (
1276
+ flags == "eddsa" ? PublicKeyAlgorithmTag . EdDsa : PublicKeyAlgorithmTag . ECDsa , DateTime . UtcNow ,
1277
+ new ECDsaPublicBcpgKey ( curveOid , new BigInteger ( 1 , qVal ) ) ) ;
1248
1278
1249
- SXprUtilities . SkipCloseParenthesis ( inputStream ) ;
1279
+ reader . SkipCloseParenthesis ( ) ;
1250
1280
1251
- byte [ ] dValue = GetDValue ( inputStream , rawPassPhrase , clearPassPhrase , curveName ) ;
1281
+ byte [ ] dValue = GetDValue ( reader , rawPassPhrase , clearPassPhrase , curveName ) ;
1252
1282
// TODO: check SHA-1 hash.
1253
1283
1254
1284
return new PgpSecretKey ( new SecretKeyPacket ( pubPacket , SymmetricKeyAlgorithmTag . Null , null , null ,
@@ -1258,51 +1288,68 @@ internal static PgpSecretKey DoParseSecretKeyFromSExpr(Stream inputStream, byte[
1258
1288
throw new PgpException ( "unknown key type found" ) ;
1259
1289
}
1260
1290
1261
- private static byte [ ] GetDValue ( Stream inputStream , byte [ ] rawPassPhrase , bool clearPassPhrase , string curveName )
1291
+ private static byte [ ] GetDValue ( SXprUtilities reader , byte [ ] rawPassPhrase , bool clearPassPhrase , string curveName )
1262
1292
{
1263
1293
string type ;
1264
- SXprUtilities . SkipOpenParenthesis ( inputStream ) ;
1294
+ reader . SkipOpenParenthesis ( ) ;
1265
1295
1266
1296
string protection ;
1267
1297
S2k s2k ;
1268
1298
byte [ ] iv ;
1269
1299
byte [ ] secKeyData ;
1270
1300
1271
- type = SXprUtilities . ReadString ( inputStream , inputStream . ReadByte ( ) ) ;
1301
+ type = reader . ReadString ( ) ;
1272
1302
if ( type . Equals ( "protected" ) )
1273
1303
{
1274
- protection = SXprUtilities . ReadString ( inputStream , inputStream . ReadByte ( ) ) ;
1304
+ protection = reader . ReadString ( ) ;
1275
1305
1276
- SXprUtilities . SkipOpenParenthesis ( inputStream ) ;
1306
+ reader . SkipOpenParenthesis ( ) ;
1277
1307
1278
- s2k = SXprUtilities . ParseS2k ( inputStream ) ;
1308
+ s2k = reader . ParseS2k ( ) ;
1279
1309
1280
- iv = SXprUtilities . ReadBytes ( inputStream , inputStream . ReadByte ( ) ) ;
1310
+ iv = reader . ReadBytes ( ) ;
1281
1311
1282
- SXprUtilities . SkipCloseParenthesis ( inputStream ) ;
1312
+ reader . SkipCloseParenthesis ( ) ;
1283
1313
1284
- secKeyData = SXprUtilities . ReadBytes ( inputStream , inputStream . ReadByte ( ) ) ;
1314
+ secKeyData = reader . ReadBytes ( ) ;
1285
1315
}
1286
1316
else
1287
1317
{
1288
1318
throw new PgpException ( "protected block not found" ) ;
1289
1319
}
1290
1320
1291
- // TODO: recognise other algorithms
1292
- KeyParameter key = PgpUtilities . DoMakeKeyFromPassPhrase ( SymmetricKeyAlgorithmTag . Aes128 , s2k , rawPassPhrase , clearPassPhrase ) ;
1321
+ // Valid values of protection: openpgp-s2k3-sha1-aes-cbc, openpgp-s2k3-ocb-aes, openpgp-native
1322
+ byte [ ] data ;
1323
+ KeyParameter key ;
1324
+
1325
+ switch ( protection )
1326
+ {
1327
+ case "openpgp-s2k3-sha1-aes-cbc" :
1328
+ key = PgpUtilities . DoMakeKeyFromPassPhrase ( SymmetricKeyAlgorithmTag . Aes128 , s2k , rawPassPhrase , clearPassPhrase ) ;
1329
+ data = RecoverKeyData ( SymmetricKeyAlgorithmTag . Aes128 , "/CBC/NoPadding" , key , iv , secKeyData , 0 , secKeyData . Length ) ;
1330
+ break ;
1331
+
1332
+ case "openpgp-s2k3-ocb-aes" :
1333
+ key = PgpUtilities . DoMakeKeyFromPassPhrase ( SymmetricKeyAlgorithmTag . Aes128 , s2k , rawPassPhrase , clearPassPhrase ) ;
1334
+ data = RecoverKeyData ( SymmetricKeyAlgorithmTag . Aes128 , "/OCB/NoPadding" , key , iv , secKeyData , 0 , secKeyData . Length ) ;
1335
+ break ;
1293
1336
1294
- byte [ ] data = RecoverKeyData ( SymmetricKeyAlgorithmTag . Aes128 , "/CBC/NoPadding" , key , iv , secKeyData , 0 , secKeyData . Length ) ;
1337
+ case "openpgp-native" :
1338
+ default :
1339
+ throw new PgpException ( protection + " key format is not supported yet" ) ;
1340
+ }
1295
1341
1296
1342
//
1297
1343
// parse the secret key S-expr
1298
1344
//
1299
1345
Stream keyIn = new MemoryStream ( data , false ) ;
1300
1346
1301
- SXprUtilities . SkipOpenParenthesis ( keyIn ) ;
1302
- SXprUtilities . SkipOpenParenthesis ( keyIn ) ;
1303
- SXprUtilities . SkipOpenParenthesis ( keyIn ) ;
1304
- String name = SXprUtilities . ReadString ( keyIn , keyIn . ReadByte ( ) ) ;
1305
- return SXprUtilities . ReadBytes ( keyIn , keyIn . ReadByte ( ) ) ;
1347
+ reader = new SXprUtilities ( keyIn ) ;
1348
+ reader . SkipOpenParenthesis ( ) ;
1349
+ reader . SkipOpenParenthesis ( ) ;
1350
+ reader . SkipOpenParenthesis ( ) ;
1351
+ String name = reader . ReadString ( ) ;
1352
+ return reader . ReadBytes ( ) ;
1306
1353
}
1307
1354
}
1308
1355
}
0 commit comments