diff --git a/.grafana.metadata b/.grafana.metadata
index 7f98944..aae365f 100644
--- a/.grafana.metadata
+++ b/.grafana.metadata
@@ -1,3 +1,3 @@
 fb987d68bb89fab4802022e58dd2986cf0851f2c SOURCES/grafana-7.5.7.tar.gz
-32016fb533ede7835c3935fad71e25a419de8c54 SOURCES/grafana-vendor-7.5.7.tar.xz
-7612761e2aeb75253a0ab7a3f546a4b7bd029871 SOURCES/grafana-webpack-7.5.7.tar.gz
+bb8f6466ba9ac8d7f50978b81ab0c2f6db73584a SOURCES/grafana-vendor-7.5.7.tar.xz
+581d2a350674bc2aa17feea341d7b8b045af5882 SOURCES/grafana-webpack-7.5.7.tar.gz
diff --git a/SOURCES/008-remove-unused-frontend-crypto.patch b/SOURCES/008-remove-unused-frontend-crypto.patch
new file mode 100644
index 0000000..8008075
--- /dev/null
+++ b/SOURCES/008-remove-unused-frontend-crypto.patch
@@ -0,0 +1,26 @@
+diff --git a/package.json b/package.json
+index 280e171804..13468e56bd 100644
+--- a/package.json
++++ b/package.json
+@@ -295,7 +295,8 @@
+   },
+   "resolutions": {
+     "caniuse-db": "1.0.30000772",
+-    "react-use-measure": "https://github.com/mckn/react-use-measure.git#remove-cjs-export"
++    "react-use-measure": "https://github.com/mckn/react-use-measure.git#remove-cjs-export",
++    "crypto-browserify": "https://registry.yarnpkg.com/@favware/skip-dependency/-/skip-dependency-1.1.1.tgz"
+   },
+   "workspaces": {
+     "packages": [
+diff --git a/scripts/webpack/webpack.common.js b/scripts/webpack/webpack.common.js
+index 3e56d31c37..a03ed1a67a 100644
+--- a/scripts/webpack/webpack.common.js
++++ b/scripts/webpack/webpack.common.js
+@@ -66,6 +66,7 @@ module.exports = {
+   },
+   node: {
+     fs: 'empty',
++    crypto: false,
+   },
+   plugins: [
+     new MonacoWebpackPlugin({
diff --git a/SOURCES/009-patch-unused-backend-crypto.patch b/SOURCES/009-patch-unused-backend-crypto.patch
new file mode 100644
index 0000000..12be571
--- /dev/null
+++ b/SOURCES/009-patch-unused-backend-crypto.patch
@@ -0,0 +1,168 @@
+diff --git a/vendor/golang.org/x/crypto/openpgp/elgamal/elgamal.go b/vendor/golang.org/x/crypto/openpgp/elgamal/elgamal.go
+new file mode 100644
+index 0000000..871e612
+--- /dev/null
++++ b/vendor/golang.org/x/crypto/openpgp/elgamal/elgamal.go
+@@ -0,0 +1,25 @@
++package elgamal
++
++import (
++	"io"
++	"math/big"
++)
++
++// PublicKey represents an ElGamal public key.
++type PublicKey struct {
++	G, P, Y *big.Int
++}
++
++// PrivateKey represents an ElGamal private key.
++type PrivateKey struct {
++	PublicKey
++	X *big.Int
++}
++
++func Encrypt(random io.Reader, pub *PublicKey, msg []byte) (c1, c2 *big.Int, err error) {
++	panic("ElGamal encryption not available")
++}
++
++func Decrypt(priv *PrivateKey, c1, c2 *big.Int) (msg []byte, err error) {
++	panic("ElGamal encryption not available")
++}
+diff --git a/vendor/golang.org/x/crypto/openpgp/packet/packet.go b/vendor/golang.org/x/crypto/openpgp/packet/packet.go
+index 9728d61..9f04c2d 100644
+--- a/vendor/golang.org/x/crypto/openpgp/packet/packet.go
++++ b/vendor/golang.org/x/crypto/openpgp/packet/packet.go
+@@ -16,7 +16,6 @@ import (
+ 	"math/big"
+ 	"math/bits"
+ 
+-	"golang.org/x/crypto/cast5"
+ 	"golang.org/x/crypto/openpgp/errors"
+ )
+ 
+@@ -487,7 +486,7 @@ func (cipher CipherFunction) KeySize() int {
+ 	case Cipher3DES:
+ 		return 24
+ 	case CipherCAST5:
+-		return cast5.KeySize
++		panic("cast5 cipher not available")
+ 	case CipherAES128:
+ 		return 16
+ 	case CipherAES192:
+@@ -517,7 +516,7 @@ func (cipher CipherFunction) new(key []byte) (block cipher.Block) {
+ 	case Cipher3DES:
+ 		block, _ = des.NewTripleDESCipher(key)
+ 	case CipherCAST5:
+-		block, _ = cast5.NewCipher(key)
++		panic("cast5 cipher not available")
+ 	case CipherAES128, CipherAES192, CipherAES256:
+ 		block, _ = aes.NewCipher(key)
+ 	}
+diff --git a/vendor/golang.org/x/crypto/openpgp/packet/symmetrically_encrypted.go b/vendor/golang.org/x/crypto/openpgp/packet/symmetrically_encrypted.go
+index 6126030..3a54c5f 100644
+--- a/vendor/golang.org/x/crypto/openpgp/packet/symmetrically_encrypted.go
++++ b/vendor/golang.org/x/crypto/openpgp/packet/symmetrically_encrypted.go
+@@ -5,13 +5,12 @@
+ package packet
+ 
+ import (
+-	"crypto/cipher"
+ 	"crypto/sha1"
+ 	"crypto/subtle"
+-	"golang.org/x/crypto/openpgp/errors"
+ 	"hash"
+ 	"io"
+-	"strconv"
++
++	"golang.org/x/crypto/openpgp/errors"
+ )
+ 
+ // SymmetricallyEncrypted represents a symmetrically encrypted byte string. The
+@@ -45,46 +44,7 @@ func (se *SymmetricallyEncrypted) parse(r io.Reader) error {
+ // packet can be read. An incorrect key can, with high probability, be detected
+ // immediately and this will result in a KeyIncorrect error being returned.
+ func (se *SymmetricallyEncrypted) Decrypt(c CipherFunction, key []byte) (io.ReadCloser, error) {
+-	keySize := c.KeySize()
+-	if keySize == 0 {
+-		return nil, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(c)))
+-	}
+-	if len(key) != keySize {
+-		return nil, errors.InvalidArgumentError("SymmetricallyEncrypted: incorrect key length")
+-	}
+-
+-	if se.prefix == nil {
+-		se.prefix = make([]byte, c.blockSize()+2)
+-		_, err := readFull(se.contents, se.prefix)
+-		if err != nil {
+-			return nil, err
+-		}
+-	} else if len(se.prefix) != c.blockSize()+2 {
+-		return nil, errors.InvalidArgumentError("can't try ciphers with different block lengths")
+-	}
+-
+-	ocfbResync := OCFBResync
+-	if se.MDC {
+-		// MDC packets use a different form of OCFB mode.
+-		ocfbResync = OCFBNoResync
+-	}
+-
+-	s := NewOCFBDecrypter(c.new(key), se.prefix, ocfbResync)
+-	if s == nil {
+-		return nil, errors.ErrKeyIncorrect
+-	}
+-
+-	plaintext := cipher.StreamReader{S: s, R: se.contents}
+-
+-	if se.MDC {
+-		// MDC packets have an embedded hash that we need to check.
+-		h := sha1.New()
+-		h.Write(se.prefix)
+-		return &seMDCReader{in: plaintext, h: h}, nil
+-	}
+-
+-	// Otherwise, we just need to wrap plaintext so that it's a valid ReadCloser.
+-	return seReader{plaintext}, nil
++	panic("OCFB cipher not available")
+ }
+ 
+ // seReader wraps an io.Reader with a no-op Close method.
+@@ -254,37 +214,5 @@ func (c noOpCloser) Close() error {
+ // written.
+ // If config is nil, sensible defaults will be used.
+ func SerializeSymmetricallyEncrypted(w io.Writer, c CipherFunction, key []byte, config *Config) (contents io.WriteCloser, err error) {
+-	if c.KeySize() != len(key) {
+-		return nil, errors.InvalidArgumentError("SymmetricallyEncrypted.Serialize: bad key length")
+-	}
+-	writeCloser := noOpCloser{w}
+-	ciphertext, err := serializeStreamHeader(writeCloser, packetTypeSymmetricallyEncryptedMDC)
+-	if err != nil {
+-		return
+-	}
+-
+-	_, err = ciphertext.Write([]byte{symmetricallyEncryptedVersion})
+-	if err != nil {
+-		return
+-	}
+-
+-	block := c.new(key)
+-	blockSize := block.BlockSize()
+-	iv := make([]byte, blockSize)
+-	_, err = config.Random().Read(iv)
+-	if err != nil {
+-		return
+-	}
+-	s, prefix := NewOCFBEncrypter(block, iv, OCFBNoResync)
+-	_, err = ciphertext.Write(prefix)
+-	if err != nil {
+-		return
+-	}
+-	plaintext := cipher.StreamWriter{S: s, W: ciphertext}
+-
+-	h := sha1.New()
+-	h.Write(iv)
+-	h.Write(iv[blockSize-2:])
+-	contents = &seMDCWriter{w: plaintext, h: h}
+-	return
++	panic("OCFB cipher not available")
+ }
diff --git a/SOURCES/010-fips.patch b/SOURCES/010-fips.patch
new file mode 100644
index 0000000..f9adee9
--- /dev/null
+++ b/SOURCES/010-fips.patch
@@ -0,0 +1,140 @@
+diff --git a/vendor/golang.org/x/crypto/internal/boring/boring.go b/vendor/golang.org/x/crypto/internal/boring/boring.go
+new file mode 100644
+index 0000000..a9c550e
+--- /dev/null
++++ b/vendor/golang.org/x/crypto/internal/boring/boring.go
+@@ -0,0 +1,74 @@
++// Copyright 2017 The Go Authors. All rights reserved.
++// Copyright 2021 Red Hat.
++// Use of this source code is governed by a BSD-style
++// license that can be found in the LICENSE file.
++
++// +build linux
++// +build !android
++// +build !no_openssl
++// +build !cmd_go_bootstrap
++// +build !msan
++
++package boring
++
++// #include "openssl_pbkdf2.h"
++// #cgo LDFLAGS: -ldl
++import "C"
++import (
++	"bytes"
++	"crypto/sha1"
++	"crypto/sha256"
++	"hash"
++	"unsafe"
++)
++
++var (
++	emptySha1   = sha1.Sum([]byte{})
++	emptySha256 = sha256.Sum256([]byte{})
++)
++
++func hashToMD(h hash.Hash) *C.GO_EVP_MD {
++	emptyHash := h.Sum([]byte{})
++
++	switch {
++	case bytes.Equal(emptyHash, emptySha1[:]):
++		return C._goboringcrypto_EVP_sha1()
++	case bytes.Equal(emptyHash, emptySha256[:]):
++		return C._goboringcrypto_EVP_sha256()
++	}
++	return nil
++}
++
++// charptr returns the address of the underlying array in b,
++// being careful not to panic when b has zero length.
++func charptr(b []byte) *C.char {
++	if len(b) == 0 {
++		return nil
++	}
++	return (*C.char)(unsafe.Pointer(&b[0]))
++}
++
++// ucharptr returns the address of the underlying array in b,
++// being careful not to panic when b has zero length.
++func ucharptr(b []byte) *C.uchar {
++	if len(b) == 0 {
++		return nil
++	}
++	return (*C.uchar)(unsafe.Pointer(&b[0]))
++}
++
++func Pbkdf2Key(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte {
++	// println("[debug] using pbkdf2 from OpenSSL")
++	ch := h()
++	md := hashToMD(ch)
++	if md == nil {
++		return nil
++	}
++
++	out := make([]byte, keyLen)
++	ok := C._goboringcrypto_PKCS5_PBKDF2_HMAC(charptr(password), C.int(len(password)), ucharptr(salt), C.int(len(salt)), C.int(iter), md, C.int(keyLen), ucharptr(out))
++	if ok != 1 {
++		panic("boringcrypto: PKCS5_PBKDF2_HMAC failed")
++	}
++	return out
++}
+diff --git a/vendor/golang.org/x/crypto/internal/boring/notboring.go b/vendor/golang.org/x/crypto/internal/boring/notboring.go
+new file mode 100644
+index 0000000..e244fb5
+--- /dev/null
++++ b/vendor/golang.org/x/crypto/internal/boring/notboring.go
+@@ -0,0 +1,16 @@
++// Copyright 2017 The Go Authors. All rights reserved.
++// Copyright 2021 Red Hat.
++// Use of this source code is governed by a BSD-style
++// license that can be found in the LICENSE file.
++
++// +build !linux !cgo android cmd_go_bootstrap msan no_openssl
++
++package boring
++
++import (
++	"hash"
++)
++
++func Pbkdf2Key(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte {
++	panic("boringcrypto: not available")
++}
+diff --git a/vendor/golang.org/x/crypto/internal/boring/openssl_pbkdf2.h b/vendor/golang.org/x/crypto/internal/boring/openssl_pbkdf2.h
+new file mode 100644
+index 0000000..6dfdf10
+--- /dev/null
++++ b/vendor/golang.org/x/crypto/internal/boring/openssl_pbkdf2.h
+@@ -0,0 +1,5 @@
++#include "/usr/lib/golang/src/crypto/internal/boring/goboringcrypto.h"
++
++DEFINEFUNC(int, PKCS5_PBKDF2_HMAC,
++    (const char *pass, int passlen, const unsigned char *salt, int saltlen, int iter, EVP_MD *digest, int keylen, unsigned char *out),
++    (pass, passlen, salt, saltlen, iter, digest, keylen, out))
+diff --git a/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go b/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go
+index 593f653..799a611 100644
+--- a/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go
++++ b/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go
+@@ -19,8 +19,11 @@ pbkdf2.Key.
+ package pbkdf2 // import "golang.org/x/crypto/pbkdf2"
+ 
+ import (
++	"crypto/boring"
+ 	"crypto/hmac"
+ 	"hash"
++
++	xboring "golang.org/x/crypto/internal/boring"
+ )
+ 
+ // Key derives a key from the password, salt and iteration count, returning a
+@@ -40,6 +43,10 @@ import (
+ // Using a higher iteration count will increase the cost of an exhaustive
+ // search but will also make derivation proportionally slower.
+ func Key(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte {
++	if boring.Enabled() {
++		return xboring.Pbkdf2Key(password, salt, iter, keyLen, h)
++	}
++
+ 	prf := hmac.New(h, password)
+ 	hashLen := prf.Size()
+ 	numBlocks := (keyLen + hashLen - 1) / hashLen
diff --git a/SOURCES/Makefile b/SOURCES/Makefile
index 1244a96..9269789 100644
--- a/SOURCES/Makefile
+++ b/SOURCES/Makefile
@@ -5,16 +5,25 @@ all: grafana-$(VER).tar.gz \
 grafana-$(VER).tar.gz:
 	wget https://github.com/grafana/grafana/archive/v$(VER)/grafana-$(VER).tar.gz
 
+ALL_PATCHES := $(wildcard *.patch)
+PATCHES_TO_APPLY := $(filter-out 009-patch-unused-backend-crypto.patch 010-fips.patch,$(ALL_PATCHES))
+
 grafana-vendor-$(VER).tar.xz: grafana-$(VER).tar.gz
 	rm -rf grafana-$(VER)
 	tar xfz grafana-$(VER).tar.gz
 
-	# patches can affect Go or Node.js dependencies
-	cd grafana-$(VER) && shopt -s nullglob && \
-		for patch in ../*.patch; do patch -p1 --fuzz=0 < $$patch; done
+	# patches can affect Go or Node.js dependencies, or the webpack
+	for patch in $(PATCHES_TO_APPLY); do patch -d grafana-$(VER) -p1 --fuzz=0 < $$patch; done
 
 	# Go
 	cd grafana-$(VER) && go mod vendor -v
+	# Remove unused crypto
+	rm grafana-$(VER)/vendor/golang.org/x/crypto/cast5/cast5.go
+	rm grafana-$(VER)/vendor/golang.org/x/crypto/ed25519/ed25519.go
+	rm grafana-$(VER)/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/const.go
+	rm grafana-$(VER)/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go
+	rm grafana-$(VER)/vendor/golang.org/x/crypto/openpgp/elgamal/elgamal.go
+	rm grafana-$(VER)/vendor/golang.org/x/crypto/openpgp/packet/ocfb.go
 	awk '$$2~/^v/ && $$4 != "indirect" {print "Provides: bundled(golang(" $$1 ")) = " substr($$2, 2)}' grafana-$(VER)/go.mod | \
 		sed -E 's/=(.*)-(.*)-(.*)/=\1-\2.\3/g' > $@.manifest
 
@@ -22,7 +31,7 @@ grafana-vendor-$(VER).tar.xz: grafana-$(VER).tar.gz
 	cd grafana-$(VER) && yarn install --pure-lockfile
 	# Remove files with licensing issues
 	find grafana-$(VER) -type d -name 'node-notifier' -prune -exec rm -r {} \;
-	find grafana-$(VER) -name '*.exe' -delete
+	find grafana-$(VER) -type f -name '*.exe' -delete
 	./list_bundled_nodejs_packages.py grafana-$(VER)/ >> $@.manifest
 
 	# Create tarball
diff --git a/SOURCES/list_bundled_nodejs_packages.py b/SOURCES/list_bundled_nodejs_packages.py
index a7c5e22..3158c2c 100755
--- a/SOURCES/list_bundled_nodejs_packages.py
+++ b/SOURCES/list_bundled_nodejs_packages.py
@@ -1,4 +1,7 @@
 #!/usr/bin/env python3
+#
+# generates Provides: bundled(npm(...)) = ... lines for each declared dependency and devDependency of package.json
+#
 import sys
 import json
 import re
diff --git a/SPECS/grafana.spec b/SPECS/grafana.spec
index 965ce3d..11c74f5 100644
--- a/SPECS/grafana.spec
+++ b/SPECS/grafana.spec
@@ -12,9 +12,15 @@ end}
 # is attached as a webpack tarball (in case of an unsuitable nodejs version on the build system)
 %define compile_frontend 0
 
+%if 0%{?rhel}
+%define enable_fips_mode 1
+%else
+%define enable_fips_mode 0
+%endif
+
 Name:             grafana
 Version:          7.5.7
-Release:          1%{?dist}
+Release:          2%{?dist}
 Summary:          Metrics dashboard and graph editor
 License:          ASL 2.0
 URL:              https://grafana.org
@@ -62,6 +68,19 @@ Patch6:           006-fix-gtime-test-32bit.patch
 
 Patch7:           007-remove-duplicate-grafana-aws-sdk-dependency.patch
 
+Patch8:           008-remove-unused-frontend-crypto.patch
+
+# The Makefile removes a few files with crypto implementations
+# from the vendor tarball, which are not used in Grafana.
+# This patch removes all references to the deleted files.
+Patch9:           009-patch-unused-backend-crypto.patch
+
+%if %{enable_fips_mode}
+# This patch modifies the x/crypto/pbkdf2 function to use OpenSSL
+# if FIPS mode is enabled.
+Patch10:          010-fips.patch
+%endif
+
 # Intersection of go_arches and nodejs_arches
 ExclusiveArch:    %{grafana_arches}
 
@@ -69,10 +88,15 @@ BuildRequires:    systemd, golang, go-srpm-macros
 %if 0%{?fedora} >= 31
 BuildRequires:    go-rpm-macros
 %endif
+
 %if %{compile_frontend}
 BuildRequires:    nodejs >= 1:14, yarnpkg
 %endif
 
+%if %{enable_fips_mode}
+BuildRequires:    openssl-devel
+%endif
+
 # omit golang debugsource, see BZ995136 and related
 %global           dwz_low_mem_die_limit 0
 %global           _debugsource_template %{nil}
@@ -451,6 +475,11 @@ rm -r plugins-bundled
 %patch5 -p1
 %patch6 -p1
 %patch7 -p1
+%patch8 -p1
+%patch9 -p1
+%if %{enable_fips_mode}
+%patch10 -p1
+%endif
 
 # Set up build subdirs and links
 mkdir -p %{_builddir}/src/github.com/grafana
@@ -580,6 +609,9 @@ export TZ=GMT
 
 %gotest ./pkg/...
 
+%if %{enable_fips_mode}
+GOLANG_FIPS=1 go test -v ./pkg/util -run TestEncryption
+%endif
 
 %files
 # binaries and wrappers
@@ -626,6 +658,10 @@ export TZ=GMT
 
 
 %changelog
+* Fri Jun 11 2021 Andreas Gerstmayr <agerstmayr@redhat.com> 7.5.7-2
+- remove unused cryptographic implementations
+- use cryptographic functions from OpenSSL if FIPS mode is enabled
+
 * Tue May 25 2021 Andreas Gerstmayr <agerstmayr@redhat.com> 7.5.7-1
 - update to 7.5.7 tagged upstream community sources, see CHANGELOG