aboutsummaryrefslogtreecommitdiffstats
path: root/sshlib/src/main/java/com/trilead/ssh2/crypto/digest/MAC.java
blob: 561599c997a33d9ddaa63d0e452533b32a901671 (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
package com.trilead.ssh2.crypto.digest;

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.Mac;
import javax.crypto.ShortBufferException;
import javax.crypto.spec.SecretKeySpec;

/**
 * MAC.
 * 
 * @author Christian Plattner, plattner@trilead.com
 * @version $Id: MAC.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $
 */
public final class MAC
{
	/**
	 * From http://tools.ietf.org/html/rfc4253
	 */
	private static final String HMAC_MD5 = "hmac-md5";

	/**
	 * From http://tools.ietf.org/html/rfc4253
	 */
	private static final String HMAC_MD5_96 = "hmac-md5-96";

	/**
	 * From http://tools.ietf.org/html/rfc4253
	 */
	private static final String HMAC_SHA1 = "hmac-sha1";

	/**
	 * From http://tools.ietf.org/html/rfc4253
	 */
	private static final String HMAC_SHA1_96 = "hmac-sha1-96";

	/**
	 * From http://tools.ietf.org/html/rfc6668
	 */
	private static final String HMAC_SHA2_256 = "hmac-sha2-256";

	/**
	 * From http://tools.ietf.org/html/rfc6668
	 */
	private static final String HMAC_SHA2_512 = "hmac-sha2-512";

	Mac mac;
	int outSize;
	int macSize;
	byte[] buffer;

	/* Higher Priority First */
	private static final String[] MAC_LIST = {
		HMAC_SHA2_256, HMAC_SHA2_512,
		HMAC_SHA1_96, HMAC_SHA1, HMAC_MD5_96, HMAC_MD5
	};

	public final static String[] getMacList()
	{
		return MAC_LIST;
	}

	public final static void checkMacList(String[] macs)
	{
		for (int i = 0; i < macs.length; i++)
			getKeyLen(macs[i]);
	}

	public final static int getKeyLen(String type)
	{
		if (HMAC_SHA1.equals(type) || HMAC_SHA1_96.equals(type))
			return 20;
		if (HMAC_MD5.equals(type) || HMAC_MD5_96.equals(type))
			return 16;
		if (HMAC_SHA2_256.equals(type))
			return 32;
		if (HMAC_SHA2_512.equals(type))
			return 64;
		throw new IllegalArgumentException("Unkown algorithm " + type);
	}

	public MAC(String type, byte[] key)
	{
		try {
			if (HMAC_SHA1.equals(type) || HMAC_SHA1_96.equals(type))
			{
				mac = Mac.getInstance("HmacSHA1");
			}
			else if (HMAC_MD5.equals(type) || HMAC_MD5_96.equals(type))
			{
				mac = Mac.getInstance("HmacMD5");
			}
			else if (HMAC_SHA2_256.equals(type))
			{
				mac = Mac.getInstance("HmacSHA256");
			}
			else if (HMAC_SHA2_512.equals(type))
			{
				mac = Mac.getInstance("HmacSHA512");
			}
			else
				throw new IllegalArgumentException("Unkown algorithm " + type);
		} catch (NoSuchAlgorithmException e) {
			throw new IllegalArgumentException("Unknown algorithm " + type, e);
		}

		macSize = mac.getMacLength();
		if (type.endsWith("-96")) {
			outSize = 12;
			buffer = new byte[macSize];
		} else {
			outSize = macSize;
			buffer = null;
		}

		try {
			mac.init(new SecretKeySpec(key, type));
		} catch (InvalidKeyException e) {
			throw new IllegalArgumentException(e);
		}
	}

	public final void initMac(int seq)
	{
		mac.reset();
		mac.update((byte) (seq >> 24));
		mac.update((byte) (seq >> 16));
		mac.update((byte) (seq >> 8));
		mac.update((byte) (seq));
	}

	public final void update(byte[] packetdata, int off, int len)
	{
		mac.update(packetdata, off, len);
	}

	public final void getMac(byte[] out, int off)
	{
		try {
			if (buffer != null) {
				mac.doFinal(buffer, 0);
				System.arraycopy(buffer, 0, out, off, out.length - off);
			} else {
				mac.doFinal(out, off);
			}
		} catch (ShortBufferException e) {
			throw new IllegalStateException(e);
		}
	}

	public final int size()
	{
		return outSize;
	}
}