diff --git a/src/pkg/crypto/cipher/gcm.go b/src/pkg/crypto/cipher/gcm.go
new file mode 100644
index 0000000000000000000000000000000000000000..2bcb469852b83f1715eeeb177ad28070e04e9e2d
--- /dev/null
+++ b/src/pkg/crypto/cipher/gcm.go
@@ -0,0 +1,350 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cipher
+
+import (
+	"crypto/subtle"
+	"errors"
+)
+
+// AEAD is a cipher mode providing authenticated encryption with associated
+// data.
+type AEAD interface {
+	// NonceSize returns the size of the nonce that must be passed to Seal
+	// and Open.
+	NonceSize() int
+
+	// Overhead returns the maximum difference between the lengths of a
+	// plaintext and ciphertext.
+	Overhead() int
+
+	// Seal encrypts and authenticates plaintext, authenticates the
+	// additional data and appends the result to dst, returning the updated
+	// slice. The nonce must be NonceSize() bytes long and unique for all
+	// time, for a given key.
+	//
+	// The plaintext and dst may alias exactly or not at all.
+	Seal(dst, nonce, plaintext, data []byte) []byte
+
+	// Open decrypts and authenticates ciphertext, authenticates the
+	// additional data and, if successful, appends the resulting plaintext
+	// to dst, returning the updated slice and true. On error, nil and
+	// false is returned. The nonce must be NonceSize() bytes long and both
+	// it and the additional data must match the value passed to Seal.
+	//
+	// The ciphertext and dst may alias exactly or not at all.
+	Open(dst, nonce, ciphertext, data []byte) ([]byte, error)
+}
+
+// gcmFieldElement represents a value in GF(2¹²⁸). In order to reflect the GCM
+// standard and make getUint64 suitable for marshaling these values, the bits
+// are stored backwards. For example:
+//   the coefficient of x⁰ can be obtained by v.low >> 63.
+//   the coefficient of x⁶³ can be obtained by v.low & 1.
+//   the coefficient of x⁶⁴ can be obtained by v.high >> 63.
+//   the coefficient of x¹²⁷ can be obtained by v.high & 1.
+type gcmFieldElement struct {
+	low, high uint64
+}
+
+// gcm represents a Galois Counter Mode with a specific key. See
+// http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf
+type gcm struct {
+	cipher Block
+	// productTable contains the first sixteen powers of the key, H.
+	// However, they are in bit reversed order. See NewGCM.
+	productTable [16]gcmFieldElement
+}
+
+// NewGCM returns the given 128-bit, block cipher wrapped in Galois Counter Mode.
+func NewGCM(cipher Block) (AEAD, error) {
+	if cipher.BlockSize() != gcmBlockSize {
+		return nil, errors.New("cipher: NewGCM requires 128-bit block cipher")
+	}
+
+	var key [gcmBlockSize]byte
+	cipher.Encrypt(key[:], key[:])
+
+	g := &gcm{cipher: cipher}
+
+	// We precompute 16 multiples of |key|. However, when we do lookups
+	// into this table we'll be using bits from a field element and
+	// therefore the bits will be in the reverse order. So normally one
+	// would expect, say, 4*key to be in index 4 of the table but due to
+	// this bit ordering it will actually be in index 0010 (base 2) = 2.
+	x := gcmFieldElement{
+		getUint64(key[:8]),
+		getUint64(key[8:]),
+	}
+	g.productTable[reverseBits(1)] = x
+
+	for i := 2; i < 16; i += 2 {
+		g.productTable[reverseBits(i)] = gcmDouble(&g.productTable[reverseBits(i/2)])
+		g.productTable[reverseBits(i+1)] = gcmAdd(&g.productTable[reverseBits(i)], &x)
+	}
+
+	return g, nil
+}
+
+const (
+	gcmBlockSize = 16
+	gcmTagSize   = 16
+	gcmNonceSize = 12
+)
+
+func (*gcm) NonceSize() int {
+	return gcmNonceSize
+}
+
+func (*gcm) Overhead() int {
+	return gcmTagSize
+}
+
+func (g *gcm) Seal(dst, nonce, plaintext, data []byte) []byte {
+	if len(nonce) != gcmNonceSize {
+		panic("cipher: incorrect nonce length given to GCM")
+	}
+
+	ret, out := sliceForAppend(dst, len(plaintext)+gcmTagSize)
+
+	// See GCM spec, section 7.1.
+	var counter, tagMask [gcmBlockSize]byte
+	copy(counter[:], nonce)
+	counter[gcmBlockSize-1] = 1
+
+	g.cipher.Encrypt(tagMask[:], counter[:])
+	gcmInc32(&counter)
+
+	g.counterCrypt(out, plaintext, &counter)
+	g.auth(out[len(plaintext):], out[:len(plaintext)], data, &tagMask)
+
+	return ret
+}
+
+var errOpen = errors.New("cipher: message authentication failed")
+
+func (g *gcm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
+	if len(nonce) != gcmNonceSize {
+		panic("cipher: incorrect nonce length given to GCM")
+	}
+
+	if len(ciphertext) < gcmTagSize {
+		return nil, errOpen
+	}
+	tag := ciphertext[len(ciphertext)-gcmTagSize:]
+	ciphertext = ciphertext[:len(ciphertext)-gcmTagSize]
+
+	// See GCM spec, section 7.1.
+	var counter, tagMask [gcmBlockSize]byte
+	copy(counter[:], nonce)
+	counter[gcmBlockSize-1] = 1
+
+	g.cipher.Encrypt(tagMask[:], counter[:])
+	gcmInc32(&counter)
+
+	var expectedTag [gcmTagSize]byte
+	g.auth(expectedTag[:], ciphertext, data, &tagMask)
+
+	if subtle.ConstantTimeCompare(expectedTag[:], tag) != 1 {
+		return nil, errOpen
+	}
+
+	ret, out := sliceForAppend(dst, len(ciphertext))
+	g.counterCrypt(out, ciphertext, &counter)
+
+	return ret, nil
+}
+
+// reverseBits reverses the order of the bits of 4-bit number in i.
+func reverseBits(i int) int {
+	i = ((i << 2) & 0xc) | ((i >> 2) & 0x3)
+	i = ((i << 1) & 0xa) | ((i >> 1) & 0x5)
+	return i
+}
+
+// gcmAdd adds two elements of GF(2¹²⁸) and returns the sum.
+func gcmAdd(x, y *gcmFieldElement) gcmFieldElement {
+	// Addition in a characteristic 2 field is just XOR.
+	return gcmFieldElement{x.low ^ y.low, x.high ^ y.high}
+}
+
+// gcmDouble returns the result of doubling an element of GF(2¹²⁸).
+func gcmDouble(x *gcmFieldElement) (double gcmFieldElement) {
+	msbSet := x.high&1 == 1
+
+	// Because of the bit-ordering, doubling is actually a right shift.
+	double.high = x.high >> 1
+	double.high |= x.low << 63
+	double.low = x.low >> 1
+
+	// If the most-significant bit was set before shifting then it,
+	// conceptually, becomes a term of x^128. This is greater than the
+	// irreducible polynomial so the result has to be reduced. The
+	// irreducible polynomial is 1+x+x^2+x^7+x^128. We can subtract that to
+	// eliminate the term at x^128 which also means subtracting the other
+	// four terms. In characteristic 2 fields, subtraction == addition ==
+	// XOR.
+	if msbSet {
+		double.low ^= 0xe100000000000000
+	}
+
+	return
+}
+
+var gcmReductionTable = []uint16{
+	0x0000, 0x1c20, 0x3840, 0x2460, 0x7080, 0x6ca0, 0x48c0, 0x54e0,
+	0xe100, 0xfd20, 0xd940, 0xc560, 0x9180, 0x8da0, 0xa9c0, 0xb5e0,
+}
+
+// mul sets y to y*H, where H is the GCM key, fixed during NewGCM.
+func (g *gcm) mul(y *gcmFieldElement) {
+	var z gcmFieldElement
+
+	for i := 0; i < 2; i++ {
+		word := y.high
+		if i == 1 {
+			word = y.low
+		}
+
+		// Multiplication works by multiplying z by 16 and adding in
+		// one of the precomputed multiples of H.
+		for j := 0; j < 64; j += 4 {
+			msw := z.high & 0xf
+			z.high >>= 4
+			z.high |= z.low << 60
+			z.low >>= 4
+			z.low ^= uint64(gcmReductionTable[msw]) << 48
+
+			// the values in |table| are ordered for
+			// little-endian bit positions. See the comment
+			// in NewGCM.
+			t := &g.productTable[word&0xf]
+
+			z.low ^= t.low
+			z.high ^= t.high
+			word >>= 4
+		}
+	}
+
+	*y = z
+}
+
+// updateBlocks extends y with more polynomial terms from blocks, based on
+// Horner's rule. There must be a multiple of gcmBlockSize bytes in blocks.
+func (g *gcm) updateBlocks(y *gcmFieldElement, blocks []byte) {
+	for len(blocks) > 0 {
+		y.low ^= getUint64(blocks)
+		y.high ^= getUint64(blocks[8:])
+		g.mul(y)
+		blocks = blocks[gcmBlockSize:]
+	}
+}
+
+// update extends y with more polynomial terms from data. If data is not a
+// multiple of gcmBlockSize bytes long then the remainder is zero padded.
+func (g *gcm) update(y *gcmFieldElement, data []byte) {
+	fullBlocks := (len(data) >> 4) << 4
+	g.updateBlocks(y, data[:fullBlocks])
+
+	if len(data) != fullBlocks {
+		var partialBlock [gcmBlockSize]byte
+		copy(partialBlock[:], data[fullBlocks:])
+		g.updateBlocks(y, partialBlock[:])
+	}
+}
+
+// gcmInc32 treats the final four bytes of counterBlock as a big-endian value
+// and increments it.
+func gcmInc32(counterBlock *[16]byte) {
+	c := 1
+	for i := gcmBlockSize - 1; i >= gcmBlockSize-4; i-- {
+		c += int(counterBlock[i])
+		counterBlock[i] = byte(c)
+		c >>= 8
+	}
+}
+
+// sliceForAppend takes a slice and a requested number of bytes. It returns a
+// slice with the contents of the given slice followed by that many bytes and a
+// second slice that aliases into it and contains only the extra bytes. If the
+// original slice has sufficient capacity then no allocation is performed.
+func sliceForAppend(in []byte, n int) (head, tail []byte) {
+	if total := len(in) + n; cap(in) >= total {
+		head = in[:total]
+	} else {
+		head = make([]byte, total)
+		copy(head, in)
+	}
+	tail = head[len(in):]
+	return
+}
+
+// counterCrypt crypts in to out using g.cipher in counter mode.
+func (g *gcm) counterCrypt(out, in []byte, counter *[gcmBlockSize]byte) {
+	var mask [gcmBlockSize]byte
+
+	for len(in) >= gcmBlockSize {
+		g.cipher.Encrypt(mask[:], counter[:])
+		gcmInc32(counter)
+
+		for i := range mask {
+			out[i] = in[i] ^ mask[i]
+		}
+		out = out[gcmBlockSize:]
+		in = in[gcmBlockSize:]
+	}
+
+	if len(in) > 0 {
+		g.cipher.Encrypt(mask[:], counter[:])
+		gcmInc32(counter)
+
+		for i := range in {
+			out[i] = in[i] ^ mask[i]
+		}
+	}
+}
+
+// auth calculates GHASH(ciphertext, additionalData), masks the result with
+// tagMask and writes the result to out.
+func (g *gcm) auth(out, ciphertext, additionalData []byte, tagMask *[gcmTagSize]byte) {
+	var y gcmFieldElement
+	g.update(&y, additionalData)
+	g.update(&y, ciphertext)
+
+	y.low ^= uint64(len(additionalData)) * 8
+	y.high ^= uint64(len(ciphertext)) * 8
+
+	g.mul(&y)
+
+	putUint64(out, y.low)
+	putUint64(out[8:], y.high)
+
+	for i := range tagMask {
+		out[i] ^= tagMask[i]
+	}
+}
+
+func getUint64(data []byte) uint64 {
+	r := uint64(data[0])<<56 |
+		uint64(data[1])<<48 |
+		uint64(data[2])<<40 |
+		uint64(data[3])<<32 |
+		uint64(data[4])<<24 |
+		uint64(data[5])<<16 |
+		uint64(data[6])<<8 |
+		uint64(data[7])
+	return r
+}
+
+func putUint64(out []byte, v uint64) {
+	out[0] = byte(v >> 56)
+	out[1] = byte(v >> 48)
+	out[2] = byte(v >> 40)
+	out[3] = byte(v >> 32)
+	out[4] = byte(v >> 24)
+	out[5] = byte(v >> 16)
+	out[6] = byte(v >> 8)
+	out[7] = byte(v)
+}
diff --git a/src/pkg/crypto/cipher/gcm_test.go b/src/pkg/crypto/cipher/gcm_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..02d421590061bac3c3a9ae2c3545115618159d72
--- /dev/null
+++ b/src/pkg/crypto/cipher/gcm_test.go
@@ -0,0 +1,175 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cipher_test
+
+import (
+	"bytes"
+	"crypto/aes"
+	"crypto/cipher"
+	"encoding/hex"
+	"testing"
+)
+
+// AES-GCM test vectors taken from gcmEncryptExtIV128.rsp from
+// http://csrc.nist.gov/groups/STM/cavp/index.html.
+var aesGCMTests = []struct {
+	key, nonce, plaintext, ad, result string
+}{
+	{
+		"11754cd72aec309bf52f7687212e8957",
+		"3c819d9a9bed087615030b65",
+		"",
+		"",
+		"250327c674aaf477aef2675748cf6971",
+	},
+	{
+		"ca47248ac0b6f8372a97ac43508308ed",
+		"ffd2b598feabc9019262d2be",
+		"",
+		"",
+		"60d20404af527d248d893ae495707d1a",
+	},
+	{
+		"77be63708971c4e240d1cb79e8d77feb",
+		"e0e00f19fed7ba0136a797f3",
+		"",
+		"7a43ec1d9c0a5a78a0b16533a6213cab",
+		"209fcc8d3675ed938e9c7166709dd946",
+	},
+	{
+		"7680c5d3ca6154758e510f4d25b98820",
+		"f8f105f9c3df4965780321f8",
+		"",
+		"c94c410194c765e3dcc7964379758ed3",
+		"94dca8edfcf90bb74b153c8d48a17930",
+	},
+	{
+		"7fddb57453c241d03efbed3ac44e371c",
+		"ee283a3fc75575e33efd4887",
+		"d5de42b461646c255c87bd2962d3b9a2",
+		"",
+		"2ccda4a5415cb91e135c2a0f78c9b2fdb36d1df9b9d5e596f83e8b7f52971cb3",
+	},
+	{
+		"ab72c77b97cb5fe9a382d9fe81ffdbed",
+		"54cc7dc2c37ec006bcc6d1da",
+		"007c5e5b3e59df24a7c355584fc1518d",
+		"",
+		"0e1bde206a07a9c2c1b65300f8c649972b4401346697138c7a4891ee59867d0c",
+	},
+	{
+		"fe47fcce5fc32665d2ae399e4eec72ba",
+		"5adb9609dbaeb58cbd6e7275",
+		"7c0e88c88899a779228465074797cd4c2e1498d259b54390b85e3eef1c02df60e743f1b840382c4bccaf3bafb4ca8429bea063",
+		"88319d6e1d3ffa5f987199166c8a9b56c2aeba5a",
+		"98f4826f05a265e6dd2be82db241c0fbbbf9ffb1c173aa83964b7cf5393043736365253ddbc5db8778371495da76d269e5db3e291ef1982e4defedaa2249f898556b47",
+	},
+	{
+		"ec0c2ba17aa95cd6afffe949da9cc3a8",
+		"296bce5b50b7d66096d627ef",
+		"b85b3753535b825cbe5f632c0b843c741351f18aa484281aebec2f45bb9eea2d79d987b764b9611f6c0f8641843d5d58f3a242",
+		"f8d00f05d22bf68599bcdeb131292ad6e2df5d14",
+		"a7443d31c26bdf2a1c945e29ee4bd344a99cfaf3aa71f8b3f191f83c2adfc7a07162995506fde6309ffc19e716eddf1a828c5a890147971946b627c40016da1ecf3e77",
+	},
+	{
+		"2c1f21cf0f6fb3661943155c3e3d8492",
+		"23cb5ff362e22426984d1907",
+		"42f758836986954db44bf37c6ef5e4ac0adaf38f27252a1b82d02ea949c8a1a2dbc0d68b5615ba7c1220ff6510e259f06655d8",
+		"5d3624879d35e46849953e45a32a624d6a6c536ed9857c613b572b0333e701557a713e3f010ecdf9a6bd6c9e3e44b065208645aff4aabee611b391528514170084ccf587177f4488f33cfb5e979e42b6e1cfc0a60238982a7aec",
+		"81824f0e0d523db30d3da369fdc0d60894c7a0a20646dd015073ad2732bd989b14a222b6ad57af43e1895df9dca2a5344a62cc57a3ee28136e94c74838997ae9823f3a",
+	},
+	{
+		"d9f7d2411091f947b4d6f1e2d1f0fb2e",
+		"e1934f5db57cc983e6b180e7",
+		"73ed042327f70fe9c572a61545eda8b2a0c6e1d6c291ef19248e973aee6c312012f490c2c6f6166f4a59431e182663fcaea05a",
+		"0a8a18a7150e940c3d87b38e73baee9a5c049ee21795663e264b694a949822b639092d0e67015e86363583fcf0ca645af9f43375f05fdb4ce84f411dcbca73c2220dea03a20115d2e51398344b16bee1ed7c499b353d6c597af8",
+		"aaadbd5c92e9151ce3db7210b8714126b73e43436d242677afa50384f2149b831f1d573c7891c2a91fbc48db29967ec9542b2321b51ca862cb637cdd03b99a0f93b134",
+	},
+	{
+		"fe9bb47deb3a61e423c2231841cfd1fb",
+		"4d328eb776f500a2f7fb47aa",
+		"f1cc3818e421876bb6b8bbd6c9",
+		"",
+		"b88c5c1977b35b517b0aeae96743fd4727fe5cdb4b5b42818dea7ef8c9",
+	},
+	{
+		"6703df3701a7f54911ca72e24dca046a",
+		"12823ab601c350ea4bc2488c",
+		"793cd125b0b84a043e3ac67717",
+		"",
+		"b2051c80014f42f08735a7b0cd38e6bcd29962e5f2c13626b85a877101",
+	},
+}
+
+func TestAESGCM(t *testing.T) {
+	for i, test := range aesGCMTests {
+		key, _ := hex.DecodeString(test.key)
+		aes, err := aes.NewCipher(key)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		nonce, _ := hex.DecodeString(test.nonce)
+		plaintext, _ := hex.DecodeString(test.plaintext)
+		ad, _ := hex.DecodeString(test.ad)
+		aesgcm, err := cipher.NewGCM(aes)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		ct := aesgcm.Seal(nil, nonce, plaintext, ad)
+		if ctHex := hex.EncodeToString(ct); ctHex != test.result {
+			t.Errorf("#%d: got %s, want %s", i, ctHex, test.result)
+			continue
+		}
+
+		plaintext2, err := aesgcm.Open(nil, nonce, ct, ad)
+		if err != nil {
+			t.Errorf("#%d: Open failed", i)
+			continue
+		}
+
+		if !bytes.Equal(plaintext, plaintext2) {
+			t.Errorf("#%d: plaintext's don't match: got %x vs %x", i, plaintext2, plaintext)
+			continue
+		}
+
+		if len(ad) > 0 {
+			ad[0] ^= 0x80
+			if _, err := aesgcm.Open(nil, nonce, ct, ad); err == nil {
+				t.Errorf("#%d: Open was successful after altering additional data", i)
+			}
+			ad[0] ^= 0x80
+		}
+
+		nonce[0] ^= 0x80
+		if _, err := aesgcm.Open(nil, nonce, ct, ad); err == nil {
+			t.Errorf("#%d: Open was successful after altering nonce", i)
+		}
+		nonce[0] ^= 0x80
+
+		ct[0] ^= 0x80
+		if _, err := aesgcm.Open(nil, nonce, ct, ad); err == nil {
+			t.Errorf("#%d: Open was successful after altering ciphertext", i)
+		}
+		ct[0] ^= 0x80
+	}
+}
+
+func BenchmarkAESGCM(b *testing.B) {
+	buf := make([]byte, 1024)
+	b.SetBytes(int64(len(buf)))
+
+	var key [16]byte
+	var nonce [12]byte
+	aes, _ := aes.NewCipher(key[:])
+	aesgcm, _ := cipher.NewGCM(aes)
+	var out []byte
+
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		out = aesgcm.Seal(out[:0], nonce[:], buf, nonce[:])
+	}
+}
diff --git a/src/pkg/go/build/deps_test.go b/src/pkg/go/build/deps_test.go
index eb2eb515a52bf053097b87ac0e5f81a3cccf8096..23cbce3652aa4e2b58f55ae2535aa5c647792efe 100644
--- a/src/pkg/go/build/deps_test.go
+++ b/src/pkg/go/build/deps_test.go
@@ -82,8 +82,9 @@ var pkgDeps = map[string][]string{
 	// L3 adds reflection and some basic utility packages
 	// and interface definitions, but nothing that makes
 	// system calls.
-	"crypto":          {"L2", "hash"}, // interfaces
-	"crypto/cipher":   {"L2"},         // interfaces
+	"crypto":          {"L2", "hash"},          // interfaces
+	"crypto/cipher":   {"L2", "crypto/subtle"}, // interfaces
+	"crypto/subtle":   {},
 	"encoding/base32": {"L2"},
 	"encoding/base64": {"L2"},
 	"encoding/binary": {"L2", "reflect"},
@@ -100,6 +101,7 @@ var pkgDeps = map[string][]string{
 		"L2",
 		"crypto",
 		"crypto/cipher",
+		"crypto/subtle",
 		"encoding/base32",
 		"encoding/base64",
 		"encoding/binary",
@@ -248,15 +250,10 @@ var pkgDeps = map[string][]string{
 	"net/mail":      {"L4", "NET", "OS"},
 	"net/textproto": {"L4", "OS", "net"},
 
-	// Support libraries for crypto that aren't L2.
-	"CRYPTO-SUPPORT": {
-		"crypto/subtle",
-	},
-
 	// Core crypto.
 	"crypto/aes":    {"L3"},
 	"crypto/des":    {"L3"},
-	"crypto/hmac":   {"L3", "CRYPTO-SUPPORT"},
+	"crypto/hmac":   {"L3"},
 	"crypto/md5":    {"L3"},
 	"crypto/rc4":    {"L3"},
 	"crypto/sha1":   {"L3"},
@@ -264,7 +261,6 @@ var pkgDeps = map[string][]string{
 	"crypto/sha512": {"L3"},
 
 	"CRYPTO": {
-		"CRYPTO-SUPPORT",
 		"crypto/aes",
 		"crypto/des",
 		"crypto/hmac",