1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.james.jdkim;
21
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.security.InvalidKeyException;
25 import java.security.KeyFactory;
26 import java.security.NoSuchAlgorithmException;
27 import java.security.PrivateKey;
28 import java.security.Signature;
29 import java.security.SignatureException;
30 import java.security.spec.InvalidKeySpecException;
31 import java.security.spec.PKCS8EncodedKeySpec;
32 import java.util.List;
33
34 import org.apache.commons.codec.binary.Base64;
35 import org.apache.james.jdkim.api.BodyHasher;
36 import org.apache.james.jdkim.api.Headers;
37 import org.apache.james.jdkim.api.SignatureRecord;
38 import org.apache.james.jdkim.exceptions.FailException;
39 import org.apache.james.jdkim.exceptions.PermFailException;
40 import org.apache.james.jdkim.impl.BodyHasherImpl;
41 import org.apache.james.jdkim.impl.Message;
42 import org.apache.james.jdkim.tagvalue.SignatureRecordImpl;
43 import org.apache.james.mime4j.MimeException;
44
45 public class DKIMSigner extends DKIMCommon {
46
47 private PrivateKey privateKey;
48 private String signatureRecordTemplate;
49
50 public DKIMSigner(String signatureRecordTemplate, PrivateKey privateKey) {
51 this.privateKey = privateKey;
52 this.signatureRecordTemplate = signatureRecordTemplate;
53 }
54
55 public SignatureRecord newSignatureRecordTemplate(String record) {
56 return new SignatureRecordImpl(record);
57 }
58
59 public BodyHasher newBodyHasher(SignatureRecord signRecord)
60 throws PermFailException {
61 return new BodyHasherImpl(signRecord);
62 }
63
64 public String sign(InputStream is) throws IOException, FailException {
65 Message message;
66 try {
67 try {
68 message = new Message(is);
69 } catch (MimeException e1) {
70 throw new PermFailException("MIME parsing exception: "
71 + e1.getMessage(), e1);
72 }
73 SignatureRecord srt = newSignatureRecordTemplate(signatureRecordTemplate);
74
75 BodyHasher bhj = newBodyHasher(srt);
76
77
78 DKIMCommon.streamCopy(message.getBodyInputStream(), bhj
79 .getOutputStream());
80
81 return sign(message, bhj);
82
83 } finally {
84 is.close();
85 }
86 }
87
88 public String sign(Headers message, BodyHasher bhj)
89 throws PermFailException {
90 byte[] computedHash = bhj.getDigest();
91
92 bhj.getSignatureRecord().setBodyHash(computedHash);
93
94 List headers = bhj.getSignatureRecord().getHeaders();
95 try {
96
97
98
99
100
101
102
103 byte[] signatureHash = signatureSign(message, bhj
104 .getSignatureRecord(), privateKey, headers);
105
106 bhj.getSignatureRecord().setSignature(signatureHash);
107
108 return "DKIM-Signature:"+bhj.getSignatureRecord().toString();
109 } catch (InvalidKeyException e) {
110 throw new PermFailException("Invalid key: " + e.getMessage(), e);
111 } catch (NoSuchAlgorithmException e) {
112 throw new PermFailException("Unknown algorythm: " + e.getMessage(),
113 e);
114 } catch (SignatureException e) {
115 throw new PermFailException("Signing exception: " + e.getMessage(),
116 e);
117 }
118 }
119
120 private byte[] signatureSign(Headers h, SignatureRecord sign, PrivateKey key, List headers)
121 throws NoSuchAlgorithmException, InvalidKeyException,
122 SignatureException, PermFailException {
123
124 Signature signature = Signature.getInstance(sign.getHashMethod()
125 .toString().toUpperCase()
126 + "with" + sign.getHashKeyType().toString().toUpperCase());
127 signature.initSign(key);
128
129 signatureCheck(h, sign, headers, signature);
130 return signature.sign();
131 }
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150 public static PrivateKey getPrivateKey(String privateKeyPKCS8)
151 throws NoSuchAlgorithmException, InvalidKeySpecException {
152 byte[] encKey = Base64.decodeBase64(privateKeyPKCS8.getBytes());
153
154 PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(encKey);
155 KeyFactory keyFactory;
156 keyFactory = KeyFactory.getInstance("RSA");
157 PrivateKey privKey = keyFactory.generatePrivate(privSpec);
158 return privKey;
159 }
160
161 }