001// SPDX-FileCopyrightText: 2018 Paul Schaub <vanitasvitae@fsfe.org> 002// 003// SPDX-License-Identifier: Apache-2.0 004 005package org.pgpainless.algorithm; 006 007import java.util.ArrayList; 008import java.util.List; 009import java.util.Map; 010import java.util.concurrent.ConcurrentHashMap; 011 012import org.bouncycastle.bcpg.sig.Features; 013 014/** 015 * An enumeration of features that may be set in the {@link Features} subpacket. 016 * 017 * @see <a href="https://tools.ietf.org/html/rfc4880#section-5.2.3.24">RFC4880: Features</a> 018 */ 019public enum Feature { 020 021 /** 022 * Support for Symmetrically Encrypted Integrity Protected Data Packets using Modification Detection Code Packets. 023 * 024 * @see <a href="https://tools.ietf.org/html/rfc4880#section-5.14"> 025 * RFC-4880 ยง5.14: Modification Detection Code Packet</a> 026 */ 027 MODIFICATION_DETECTION(Features.FEATURE_MODIFICATION_DETECTION), 028 029 /** 030 * Support for Authenticated Encryption with Additional Data (AEAD). 031 * If a key announces this feature, it signals support for consuming AEAD Encrypted Data Packets. 032 * 033 * NOTE: PGPAINLESS DOES NOT YET SUPPORT THIS FEATURE!!! 034 * 035 * @see <a href="https://openpgp-wg.gitlab.io/rfc4880bis/#name-aead-encrypted-data-packet-"> 036 * AEAD Encrypted Data Packet</a> 037 */ 038 AEAD_ENCRYPTED_DATA(Features.FEATURE_AEAD_ENCRYPTED_DATA), 039 040 /** 041 * If a key announces this feature, it is a version 5 public key. 042 * The version 5 format is similar to the version 4 format except for the addition of a count for the key material. 043 * This count helps to parse secret key packets (which are an extension of the public key packet format) in the case 044 * of an unknown algorithm. 045 * In addition, fingerprints of version 5 keys are calculated differently from version 4 keys. 046 * 047 * NOTE: PGPAINLESS DOES NOT YET SUPPORT THIS FEATURE!!! 048 * 049 * @see <a href="https://openpgp-wg.gitlab.io/rfc4880bis/#name-public-key-packet-formats"> 050 * Public-Key Packet Formats</a> 051 */ 052 VERSION_5_PUBLIC_KEY(Features.FEATURE_VERSION_5_PUBLIC_KEY) 053 ; 054 055 private static final Map<Byte, Feature> MAP = new ConcurrentHashMap<>(); 056 057 static { 058 for (Feature f : Feature.values()) { 059 MAP.put(f.featureId, f); 060 } 061 } 062 063 public static Feature fromId(byte id) { 064 return MAP.get(id); 065 } 066 067 private final byte featureId; 068 069 Feature(byte featureId) { 070 this.featureId = featureId; 071 } 072 073 public byte getFeatureId() { 074 return featureId; 075 } 076 077 /** 078 * Convert a bitmask into a list of {@link KeyFlag KeyFlags}. 079 * 080 * @param bitmask bitmask 081 * @return list of key flags encoded by the bitmask 082 */ 083 public static List<Feature> fromBitmask(int bitmask) { 084 List<Feature> features = new ArrayList<>(); 085 for (Feature f : Feature.values()) { 086 if ((bitmask & f.featureId) != 0) { 087 features.add(f); 088 } 089 } 090 return features; 091 } 092 093 /** 094 * Encode a list of {@link KeyFlag KeyFlags} into a bitmask. 095 * 096 * @param features list of flags 097 * @return bitmask 098 */ 099 public static byte toBitmask(Feature... features) { 100 byte mask = 0; 101 for (Feature f : features) { 102 mask |= f.featureId; 103 } 104 return mask; 105 } 106}