Subversion Repositories Programming Utils

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
86 rm5248 1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one
3
 * or more contributor license agreements.  See the NOTICE file
4
 * distributed with this work for additional information
5
 * regarding copyright ownership.  The ASF licenses this file
6
 * to you under the Apache License, Version 2.0 (the
7
 * "License"); you may not use this file except in compliance
8
 * with the License.  You may obtain a copy of the License at
9
 *
10
 *   http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing,
13
 * software distributed under the License is distributed on an
14
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
 * KIND, either express or implied.  See the License for the
16
 * specific language governing permissions and limitations
17
 * under the License.
18
 */
19
package org.apache.sshd.common.signature;
20
 
21
import java.io.IOException;
22
import java.math.BigInteger;
23
import java.security.spec.ECParameterSpec;
24
 
25
import org.apache.sshd.common.KeyPairProvider;
26
import org.apache.sshd.common.NamedFactory;
27
import org.apache.sshd.common.Signature;
28
import org.apache.sshd.common.cipher.ECCurves;
29
import org.apache.sshd.common.util.Buffer;
30
 
31
/**
32
 * Signature algorithm for EC keys using ECDSA. There
33
 *
34
 * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
35
 */
36
public class SignatureECDSA extends AbstractSignature {
37
 
38
    /**
39
     * Signature algorithm for curves of above 384 bits.
40
     */
41
    private static final String SIGNATURE_ALGORITHM_512 = "SHA512withECDSA";
42
 
43
    /**
44
     * Signature algorithm for curves from 256 to 384 bits.
45
     */
46
    private static final String SIGNATURE_ALGORITHM_384 = "SHA384withECDSA";
47
 
48
    /**
49
     * Signature algorithm for curves of 256 bits and below.
50
     */
51
    private static final String SIGNATURE_ALGORITHM_256 = "SHA256withECDSA";
52
 
53
    /**
54
     * A named factory for ECDSA signatures of NIST P-256
55
     */
56
    public static class NISTP256Factory implements NamedFactory<Signature> {
57
 
58
        public String getName() {
59
            return KeyPairProvider.ECDSA_SHA2_NISTP256;
60
        }
61
 
62
        public Signature create() {
63
            return new SignatureECDSA(SIGNATURE_ALGORITHM_256);
64
        }
65
    }
66
 
67
    /**
68
     * A named factory for ECDSA signatures of NIST P-384
69
     */
70
    public static class NISTP384Factory implements NamedFactory<Signature> {
71
 
72
        public String getName() {
73
            return KeyPairProvider.ECDSA_SHA2_NISTP384;
74
        }
75
 
76
        public Signature create() {
77
            return new SignatureECDSA(SIGNATURE_ALGORITHM_384);
78
        }
79
    }
80
 
81
    /**
82
     * A named factory for ECDSA signatures of NIST P-521
83
     */
84
    public static class NISTP521Factory implements NamedFactory<Signature> {
85
 
86
        public String getName() {
87
            return KeyPairProvider.ECDSA_SHA2_NISTP521;
88
        }
89
 
90
        public Signature create() {
91
            return new SignatureECDSA(SIGNATURE_ALGORITHM_512);
92
        }
93
    }
94
 
95
    protected SignatureECDSA(String algo) {
96
        super(algo);
97
    }
98
 
99
    public static Signature getByCurveSize(ECParameterSpec params) {
100
        int curveSize = ECCurves.getCurveSize(params);
101
        if (curveSize <= 256) {
102
            return new SignatureECDSA(SIGNATURE_ALGORITHM_256);
103
        } else if (curveSize <= 384) {
104
            return new SignatureECDSA(SIGNATURE_ALGORITHM_384);
105
        } else {
106
            return new SignatureECDSA(SIGNATURE_ALGORITHM_512);
107
        }
108
    }
109
 
110
    public byte[] sign() throws Exception {
111
        byte[] sig = signature.sign();
112
 
113
        if ((sig[0] != 0x30) || (sig[1] != sig.length - 2) || (sig[2] != 0x02)) {
114
            throw new IOException("Invalid signature format");
115
        }
116
 
117
        int rLength = sig[3];
118
        if ((rLength + 6 > sig.length) || (sig[4 + rLength] != 0x02)) {
119
            throw new IOException("Invalid signature format");
120
        }
121
 
122
        int sLength = sig[5 + rLength];
123
        if (6 + rLength + sLength > sig.length) {
124
            throw new IOException("Invalid signature format");
125
        }
126
 
127
        byte[] rArray = new byte[rLength];
128
        byte[] sArray = new byte[sLength];
129
 
130
        System.arraycopy(sig, 4, rArray, 0, rLength);
131
        System.arraycopy(sig, 6 + rLength, sArray, 0, sLength);
132
 
133
        BigInteger r = new BigInteger(rArray);
134
        BigInteger s = new BigInteger(sArray);
135
 
136
        // Write the <r,s> to its own types writer.
137
        Buffer rsBuf = new Buffer();
138
        rsBuf.putMPInt(r);
139
        rsBuf.putMPInt(s);
140
 
141
        return rsBuf.getCompactData();
142
    }
143
 
144
    public boolean verify(byte[] sig) throws Exception {
145
        sig = extractSig(sig);
146
 
147
        Buffer rsBuf = new Buffer(sig);
148
        byte[] rArray = rsBuf.getMPIntAsBytes();
149
        byte[] sArray = rsBuf.getMPIntAsBytes();
150
 
151
        if (rsBuf.available() != 0) {
152
            throw new IOException("Signature had padding");
153
        }
154
 
155
        // ASN.1
156
        int frst = ((rArray[0] & 0x80) != 0 ? 1 : 0);
157
        int scnd = ((sArray[0] & 0x80) != 0 ? 1 : 0);
158
 
159
        int length = rArray.length + sArray.length + 6 + frst + scnd;
160
        byte[] tmp = new byte[length];
161
        tmp[0] = (byte) 0x30;
162
        tmp[1] = (byte) (rArray.length + sArray.length + 4);
163
        tmp[1] += frst;
164
        tmp[1] += scnd;
165
        tmp[2] = (byte) 0x02;
166
        tmp[3] = (byte) rArray.length;
167
        tmp[3] += frst;
168
        System.arraycopy(rArray, 0, tmp, 4 + frst, rArray.length);
169
        tmp[4 + tmp[3]] = (byte) 0x02;
170
        tmp[5 + tmp[3]] = (byte) sArray.length;
171
        tmp[5 + tmp[3]] += scnd;
172
        System.arraycopy(sArray, 0, tmp, 6 + tmp[3] + scnd, sArray.length);
173
        sig = tmp;
174
 
175
        return signature.verify(sig);
176
    }
177
 
178
}