001// SPDX-FileCopyrightText: 2020 Paul Schaub <vanitasvitae@fsfe.org>, 2021 Flowcrypt a.s. 002// 003// SPDX-License-Identifier: Apache-2.0 004 005package org.pgpainless.key.info; 006 007import org.bouncycastle.asn1.ASN1ObjectIdentifier; 008import org.bouncycastle.asn1.gnu.GNUObjectIdentifiers; 009import org.bouncycastle.bcpg.ECDHPublicBCPGKey; 010import org.bouncycastle.bcpg.ECDSAPublicBCPGKey; 011import org.bouncycastle.bcpg.ECPublicBCPGKey; 012import org.bouncycastle.bcpg.EdDSAPublicBCPGKey; 013import org.bouncycastle.bcpg.S2K; 014import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; 015import org.bouncycastle.openpgp.PGPPublicKey; 016import org.bouncycastle.openpgp.PGPSecretKey; 017import org.pgpainless.algorithm.PublicKeyAlgorithm; 018import org.pgpainless.key.generation.type.eddsa.EdDSACurve; 019 020public class KeyInfo { 021 022 private final PGPSecretKey secretKey; 023 private final PGPPublicKey publicKey; 024 025 public KeyInfo(PGPSecretKey secretKey) { 026 this.secretKey = secretKey; 027 this.publicKey = secretKey.getPublicKey(); 028 } 029 030 public KeyInfo(PGPPublicKey publicKey) { 031 this.publicKey = publicKey; 032 this.secretKey = null; 033 } 034 035 public String getCurveName() { 036 return getCurveName(publicKey); 037 } 038 039 /** 040 * Returns indication that a contained secret key is encrypted. 041 * 042 * @return true if secret key is encrypted, false if secret key is not encrypted or there is public key only. 043 */ 044 public boolean isEncrypted() { 045 return secretKey != null && isEncrypted(secretKey); 046 } 047 048 /** 049 * Returns indication that a contained secret key is not encrypted. 050 * 051 * @return true if secret key is not encrypted or there is public key only, false if secret key is encrypted. 052 */ 053 public boolean isDecrypted() { 054 return secretKey == null || isDecrypted(secretKey); 055 } 056 057 /** 058 * Returns indication that a contained secret key has S2K of a type GNU_DUMMY_S2K. 059 * 060 * @return true if secret key has S2K of a type GNU_DUMMY_S2K, false if there is public key only, 061 * or S2K on the secret key is absent or not of a type GNU_DUMMY_S2K. 062 */ 063 public boolean hasDummyS2K() { 064 return secretKey != null && hasDummyS2K(secretKey); 065 } 066 067 public static String getCurveName(PGPPublicKey publicKey) { 068 PublicKeyAlgorithm algorithm = PublicKeyAlgorithm.fromId(publicKey.getAlgorithm()); 069 ECPublicBCPGKey key; 070 switch (algorithm) { 071 case ECDSA: { 072 key = (ECDSAPublicBCPGKey) publicKey.getPublicKeyPacket().getKey(); 073 break; 074 } 075 case ECDH: { 076 key = (ECDHPublicBCPGKey) publicKey.getPublicKeyPacket().getKey(); 077 break; 078 } 079 case EDDSA: { 080 key = (EdDSAPublicBCPGKey) publicKey.getPublicKeyPacket().getKey(); 081 break; 082 } 083 default: 084 throw new IllegalArgumentException("Not an elliptic curve public key (" + algorithm + ")"); 085 } 086 return getCurveName(key); 087 } 088 089 public static String getCurveName(ECPublicBCPGKey key) { 090 ASN1ObjectIdentifier identifier = key.getCurveOID(); 091 092 // Workaround for ECUtil not recognizing ed25519 093 if (identifier.equals(GNUObjectIdentifiers.Ed25519)) { 094 return EdDSACurve._Ed25519.getName(); 095 } 096 097 return ECUtil.getCurveName(identifier); 098 } 099 100 /** 101 * Returns indication that a secret key is encrypted. 102 * 103 * @param secretKey A secret key to examine. 104 * @return true if secret key is encrypted, false otherwise. 105 */ 106 public static boolean isEncrypted(PGPSecretKey secretKey) { 107 return secretKey.getS2KUsage() != 0; 108 } 109 110 /** 111 * Returns indication that a secret key is not encrypted. 112 * 113 * @param secretKey A secret key to examine. 114 * @return true if secret key is encrypted, false otherwise. 115 */ 116 public static boolean isDecrypted(PGPSecretKey secretKey) { 117 return secretKey.getS2KUsage() == 0; 118 } 119 120 /** 121 * Returns indication that a secret key has S2K of a type GNU_DUMMY_S2K. 122 * 123 * @param secretKey A secret key to examine. 124 * @return true if secret key has S2K of a type GNU_DUMMY_S2K, false otherwise. 125 */ 126 public static boolean hasDummyS2K(PGPSecretKey secretKey) { 127 final S2K s2k = secretKey.getS2K(); 128 return s2k != null && s2k.getType() == S2K.GNU_DUMMY_S2K; 129 } 130}