aboutsummaryrefslogtreecommitdiffstats
path: root/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/RainbowKeyFactorySpi.java
blob: 614e07965fa38b9a1b86402ffe30f92c1ed97c97 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
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
91
92
93
94
95
96
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
package org.spongycastle.pqc.jcajce.provider.rainbow;

import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyFactorySpi;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import org.spongycastle.asn1.ASN1Primitive;
import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
import org.spongycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
import org.spongycastle.pqc.asn1.RainbowPrivateKey;
import org.spongycastle.pqc.asn1.RainbowPublicKey;
import org.spongycastle.pqc.jcajce.spec.RainbowPrivateKeySpec;
import org.spongycastle.pqc.jcajce.spec.RainbowPublicKeySpec;


/**
 * This class transforms Rainbow keys and Rainbow key specifications.
 *
 * @see BCRainbowPublicKey
 * @see RainbowPublicKeySpec
 * @see BCRainbowPrivateKey
 * @see RainbowPrivateKeySpec
 */
public class RainbowKeyFactorySpi
    extends KeyFactorySpi
    implements AsymmetricKeyInfoConverter
{
    /**
     * Converts, if possible, a key specification into a
     * {@link BCRainbowPrivateKey}. Currently, the following key specifications
     * are supported: {@link RainbowPrivateKeySpec}, {@link PKCS8EncodedKeySpec}.
     * <p/>
     * <p/>
     * <p/>
     * The ASN.1 definition of the key structure is
     * <p/>
     * <pre>
     *   RainbowPrivateKey ::= SEQUENCE {
     *     oid        OBJECT IDENTIFIER         -- OID identifying the algorithm
     *     A1inv      SEQUENCE OF OCTET STRING  -- inversed matrix of L1
     *     b1         OCTET STRING              -- translation vector of L1
     *     A2inv      SEQUENCE OF OCTET STRING  -- inversed matrix of L2
     *     b2         OCTET STRING              -- translation vector of L2
     *     vi         OCTET STRING              -- num of elmts in each Set S
     *     layers     SEQUENCE OF Layer         -- layers of F
     *   }
     *
     *   Layer             ::= SEQUENCE OF Poly
     *   Poly              ::= SEQUENCE {
     *     alpha      SEQUENCE OF OCTET STRING
     *     beta       SEQUENCE OF OCTET STRING
     *     gamma      OCTET STRING
     *     eta        OCTET
     *   }
     * </pre>
     * <p/>
     * <p/>
     *
     * @param keySpec the key specification
     * @return the Rainbow private key
     * @throws InvalidKeySpecException if the KeySpec is not supported.
     */
    public PrivateKey engineGeneratePrivate(KeySpec keySpec)
        throws InvalidKeySpecException
    {
        if (keySpec instanceof RainbowPrivateKeySpec)
        {
            return new BCRainbowPrivateKey((RainbowPrivateKeySpec)keySpec);
        }
        else if (keySpec instanceof PKCS8EncodedKeySpec)
        {
            // get the DER-encoded Key according to PKCS#8 from the spec
            byte[] encKey = ((PKCS8EncodedKeySpec)keySpec).getEncoded();

            try
            {
                return generatePrivate(PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(encKey)));
            }
            catch (Exception e)
            {
                throw new InvalidKeySpecException(e.toString());
            }
        }

        throw new InvalidKeySpecException("Unsupported key specification: "
            + keySpec.getClass() + ".");
    }

    /**
     * Converts, if possible, a key specification into a
     * {@link BCRainbowPublicKey}. Currently, the following key specifications are
     * supported:{@link X509EncodedKeySpec}.
     * <p/>
     * <p/>
     * <p/>
     * The ASN.1 definition of a public key's structure is
     * <p/>
     * <pre>
     *    RainbowPublicKey ::= SEQUENCE {
     *      oid            OBJECT IDENTIFIER        -- OID identifying the algorithm
     *      docLength      Integer                  -- length of signable msg
     *      coeffquadratic SEQUENCE OF OCTET STRING -- quadratic (mixed) coefficients
     *      coeffsingular  SEQUENCE OF OCTET STRING -- singular coefficients
     *      coeffscalar       OCTET STRING             -- scalar coefficients
     *       }
     * </pre>
     * <p/>
     * <p/>
     *
     * @param keySpec the key specification
     * @return the Rainbow public key
     * @throws InvalidKeySpecException if the KeySpec is not supported.
     */
    public PublicKey engineGeneratePublic(KeySpec keySpec)
        throws InvalidKeySpecException
    {
        if (keySpec instanceof RainbowPublicKeySpec)
        {
            return new BCRainbowPublicKey((RainbowPublicKeySpec)keySpec);
        }
        else if (keySpec instanceof X509EncodedKeySpec)
        {
            // get the DER-encoded Key according to X.509 from the spec
            byte[] encKey = ((X509EncodedKeySpec)keySpec).getEncoded();

            // decode the SubjectPublicKeyInfo data structure to the pki object
            try
            {
                return generatePublic(SubjectPublicKeyInfo.getInstance(encKey));
            }
            catch (Exception e)
            {
                throw new InvalidKeySpecException(e.toString());
            }
        }

        throw new InvalidKeySpecException("Unknown key specification: " + keySpec + ".");
    }

    /**
     * Converts a given key into a key specification, if possible. Currently the
     * following specs are supported:
     * <ul>
     * <li>for RainbowPublicKey: X509EncodedKeySpec, RainbowPublicKeySpec
     * <li>for RainbowPrivateKey: PKCS8EncodedKeySpec, RainbowPrivateKeySpec
     * </ul>
     *
     * @param key     the key
     * @param keySpec the key specification
     * @return the specification of the CMSS key
     * @throws InvalidKeySpecException if the key type or key specification is not supported.
     */
    public final KeySpec engineGetKeySpec(Key key, Class keySpec)
        throws InvalidKeySpecException
    {
        if (key instanceof BCRainbowPrivateKey)
        {
            if (PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec))
            {
                return new PKCS8EncodedKeySpec(key.getEncoded());
            }
            else if (RainbowPrivateKeySpec.class.isAssignableFrom(keySpec))
            {
                BCRainbowPrivateKey privKey = (BCRainbowPrivateKey)key;
                return new RainbowPrivateKeySpec(privKey.getInvA1(), privKey
                    .getB1(), privKey.getInvA2(), privKey.getB2(), privKey
                    .getVi(), privKey.getLayers());
            }
        }
        else if (key instanceof BCRainbowPublicKey)
        {
            if (X509EncodedKeySpec.class.isAssignableFrom(keySpec))
            {
                return new X509EncodedKeySpec(key.getEncoded());
            }
            else if (RainbowPublicKeySpec.class.isAssignableFrom(keySpec))
            {
                BCRainbowPublicKey pubKey = (BCRainbowPublicKey)key;
                return new RainbowPublicKeySpec(pubKey.getDocLength(), pubKey
                    .getCoeffQuadratic(), pubKey.getCoeffSingular(), pubKey
                    .getCoeffScalar());
            }
        }
        else
        {
            throw new InvalidKeySpecException("Unsupported key type: "
                + key.getClass() + ".");
        }

        throw new InvalidKeySpecException("Unknown key specification: "
            + keySpec + ".");
    }

    /**
     * Translates a key into a form known by the FlexiProvider. Currently the
     * following key types are supported: RainbowPrivateKey, RainbowPublicKey.
     *
     * @param key the key
     * @return a key of a known key type
     * @throws InvalidKeyException if the key is not supported.
     */
    public final Key engineTranslateKey(Key key)
        throws InvalidKeyException
    {
        if (key instanceof BCRainbowPrivateKey || key instanceof BCRainbowPublicKey)
        {
            return key;
        }

        throw new InvalidKeyException("Unsupported key type");
    }

    public PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
        throws IOException
    {
        RainbowPrivateKey pKey = RainbowPrivateKey.getInstance(keyInfo.parsePrivateKey());

        return new BCRainbowPrivateKey(pKey.getInvA1(), pKey.getB1(), pKey.getInvA2(), pKey.getB2(), pKey.getVi(), pKey.getLayers());
    }

    public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
        throws IOException
    {
        RainbowPublicKey pKey = RainbowPublicKey.getInstance(keyInfo.parsePublicKey());

        return new BCRainbowPublicKey(pKey.getDocLength(), pKey.getCoeffQuadratic(), pKey.getCoeffSingular(), pKey.getCoeffScalar());
    }
}