Blog by Oleg Fomenko

SQL injections near us

Today let’s talk a little about more practical security staff. SQL injections is an old kind of security vulnerability that allows malicious user to execute arbitrary SQL script on you backend. It often causes because of lack of validation on url query or path parameters that can be applied to the SQL query on your backend. Nowadays, most of popular frameworks implements a proper validation during SQL construction but if you will try to construct the script by yourself (without using of popular DAO code generators or built-in SQL library methods) you can miss such validation and create a big hole in your security.

Let’s take a look on the following example:

stmt := squirrel.Select("*").From("public.users")

params := unsecuresqllib.OffsetPageParams{
    Limit:      1,
    Order:      "desc",
    PageNumber: 0,
}

// unsecure ApplyTo method with arguments "sql statement" and "column to apply".
// The last argument causes vulnerability if not validated.
stmt = params.ApplyTo(stmt, "id asc; delete from public.users where id=1; select * from public.users order by id")

str, _, _ := stmt.ToSql()
fmt.Println(str)

// User represents a row from 'public.users'.
type User struct {
    ID   uint64 `db:"id" json:"id" structs:"-"`        // id
    Name string `db:"name" json:"name" structs:"name"` // name
}

var users []User
if err := db.SelectContext(context.TODO(), &users, stmt); err != nil {
    panic(err)
}

For the table users with only two columns using an unsecure library (I won’t tell you which one) the simple SELECT query can be modified by applying order params to drop the entry from this table. This code snippet applies some params to some statement and some column but the column value is not validated anywhere in the code. Under the hood library executed stmt = stmt.OrderBy(fmt.Sprintf("%s %s", col, p.Order)), so the final query that will be submitted to the database will be: SELECT * FROM public.users ORDER BY id asc; delete from public.users where id=1; select * from public.users order by id desc LIMIT 1 OFFSET 0

EdDSA signature challenge

For the EdDSA signature protocol (that is based on Schnorr authentication scheme) it is required to understand why and how the challenge is generated. I’ve mentioned earlier that for the challenge generation in the non-interactive protocol we are using the Fiat-Shamir heuristics. The basic idea is to generate challenges using the hash of all input data. It is necessary to highlight that we have to include all input data into the hash, otherwise malicious user can be able to manipulate information that was not included and fixed in hash.

Let’s take a look to the example of challenge generation in EdDSA: it uses the \(c = Hash(aG, K, m)\) and \(r = a + c* k\) to verify later that \(rG = aG + \hat{c}K\). Using such an approach the signer can not manipulate signature \((A, r)\) because it’s data is fixed in the challenge. But imagine if we are not including the \(aG\) into the challenge. Then, malicious signer without any knowledge of private key \(k\) can select a random \(r\) and put the signature as \(( A = rG - cK, r)\). It’s easy to check that such signature passes the verification because verifier can not check that \(A\) value has been generated randomly and before challenge generation.

How Monero RingCT works?

It wasn’t a coincidence that we were talking about *SAG signatures earlier. MLSAG signatures became one of the bases for Monero blockchain confidentiality and anonymity. Using them, users can create ring signature for spending assets from one of the keys and nobody will be able to answer “what tokens have been spent?” or “have some certain tokens been spent?”. This post will describe how RingCT works in Monero and how such transactions are built.

First of all, let’s take a look on the storage model. Monero uses UTXO-based architecture for storing balances as well as Bitcoin, so in transactions inputs users operate other transaction outputs. Transaction output constitutes a pair of elliptic curve points that represents user stealth (one-time) address and hidden amount in Pedersen commitment of form \(C^a = x\cdot G + a\cdot H\), where \(x\) is a commitment blinding.

Stealth addresses is an approach when sender can transfer money to the generated one-time address of recipient and nobody will be able to understand that certain two users had any kind of interaction. More precisely, receiver can share two keys \((K^v, K^s)\) - view key and spend key. Then, sender during the transaction creation will generate a random value \(r\) and using it will generate a one-time recipient address as \(K^O = H(r\cdot K^v)\cdot G + K^s\). Also, \(r\cdot G\) will be added to the transaction extra data and called “transaction public key”. Receiver, has to monitor all transactions and using public transaction data (\(K^O\) and \(rG\)) check if \(K^O - H(k^v\cdot rG)\cdot G = K^s\). If yes - user understands that he is a receiver of these coins and can also calculate the private key \(k^O = H( k^v\cdot rG) + k^S\).

So, imagine user wants to transfer some coins using output from other transaction \((K^a_i, C^a_i)\) where \(i\in\{1,...,m\}\) for the input and \((K^b_j, C^b_j)\) where \(j\in\{1,...,p\}\) for the output (\(K^b_i\) is a receiver one-time address and \(C^b_j = y_j\cdot G + b_j\cdot H\)). To achieve additional confidentiality, users generates \(m\) pseudo-output commitments \(\hat{C}^a_i\) with same amounts but different blinding in a such way that \(\sum x_i' - \sum y_j = 0\). It’s obvious that using such construction \(\sum \hat{C}^a_i - \sum C^b_j = 0\), so we can convince verifier that sum of input coins equals to the output. Also, note that for every \(i\) sender knows the private key for zero-value commitment \(C^a_i -\hat{C}^a_i= (x_i - x_i')\cdot G = z_i\cdot G\).

Then, for every input \(i\) sender selects a random ring of size \(v+1\) with form:

Ring for RingCT

User can generate a MLSAG signature for using secrets for \(\pi\) position: \(k_{\pi,j}\) for public key \(K_{\pi,j}\) and \(z_j\) for zero-value commitment \(C^a_ {\pi,i} - \hat{C}^a_{\pi,i} = (x_{\pi,i} - x'_{\pi,i})G\). Also, sender attaches the key image for his key \(K_ {\pi,i}\). Because this key should be a one-time address we can consider that it can be used only once. So, if there is any included into the block transaction exist with same key image then we faced the try of double-spending of some output. Finally, the RingCT transaction (4 equals to type RCTTypeBulletproof2) consist of:

Tx for RingCT

In conclusion, usage of stealth addresses in a couple with ring signatures and pseudo outputs allows user’s to create an untraceable transactions with hidden amounts. In particular, stealth addresses helps to hide the connection between users while ring signatures hides the real output that will be transferred. Finally, pseudo outputs is used to achieve verification of transacted sum of coins without compromising the achieved anonymity.

Schnorr Ring signatures - Part 3

Finally, finishing the posts about ring signatures based on Schnorr authentication protocol we are able to overview the Multilayer Linkable Spontaneous Anonymous Group (MLSAG) signature protocol. This protocol provides an opportunity to generate signature with several signers while they are all still hidden in the ring. So, given the ring \(R = \{K_ {i,j}\}\) for \(i \in \{1,2,...n\}\) and \(j \in \{1,2,...m\}\) where we know the private keys \(k_{x,j}\) of the keys with secret position \(x\) for corresponding public keys \(K_{x,j}\) for \(j \in \{1,2,...m\}\). The MLSAG protocol has a lot in common with bLSAG protocol:

MLSAG signing

To verify such signature firstly verifier checks \(\forall j \in \{1,2...m\}: l\cdot\hat{K}_j = 0\) where \(l\) is the prime order of the big subgroup of our elliptic curve. Then, for the every \(i = 1, 2, ..., n\) (replacing \(n + 1 \rightarrow 1\)) verifier calculates \(c_{i+1} = H( m, [r_{i,1}\cdot G + c_i\cdot K_{i,1}], [r_{i,1}\cdot H_p(K_{i,1}) + c_i\cdot\hat{K}_1], ...)\) and checks that \(c_1 = c_1'\).

Finally, if for the two different signatures \(S_1\) and \(S_2\) such indexes \(i,j\) exist that \(\hat{K}_{S_1,i} = \hat{K}_{S_2,j}\) then these signatures are linked by signing from the same key.

In addition, using signatures linking and one-time stealth addresses Monero blockchain solves a double-spending problem: if transaction contains the key image that already has been included into the previous block then in seems to be a double-spending.

Ring signatures using Schnorr

Schnorr Ring signatures - Part 2

Linkability is a property that describes relation between two signatures. If the protocol has such property then given two different signatures (ring signatures) it becomes possible to check that them have been produced by the same signer. Linkability in a couple with anonymity property gives verifier an opportunity to check this relation without revealing any information about signer.

Back’s Linkable Spontaneous Anonymous Group (bLSAG) signature protocol as a modification of the described in previous post SAG protocol introduces the ring signature with characterized by anonymity, linkability properties. Before going thought the protocol let’s describe the special hash function \(H_p(x) \rightarrow \mathbb{G}\) the gives as the result a point in curve (DL problem can not be solved with overwhelming probability). So, for the given ring \(R = \{K_1, K_2, ..., K_d\}\) where we know the private key \(k_x\) of the key with secret position \(x\), bLSAG protocol can be defined as follows:

  1. Calculate key image \(\hat{K} = k_x\cdot H_p(K_x)\).
  2. Generate random key \(a\) and \(r_i\) for all \(i\) except of \(i = x\).
  3. Put \(c_{x+1} = H(m, [a\cdot G], [a\cdot H_p(K_x)])\).
  4. Then, for every \(i = x+1, x+2, ..., d, 1, 2, ..., x-1\) (replacing \(d + 1 \rightarrow 1\)) calculate \(c_{i+1} = H( m, [r_i\cdot G + c_i\cdot K_i], [r_i\cdot H_p(K_i) + c_i\cdot\hat{K}])\).
  5. Put the response \(r_x = a - c_xk_x\).
  6. Define the signature \((c_1, r_1, ... , r_d)\), ring \(R\) and key image \(\hat{K}\).

To verify such signature firstly verifier checks that \(l\cdot\hat{K} = 0\) where \(l\) is the prime order of the big subgroup of our elliptic curve. This is required because malicious signer can select points from the subgroup of small cofactor \(h\) that can affect linkability property. Then, for the every \(i = 1, 2, ..., d\) (replacing \(d + 1 \rightarrow 1\)) verifier calculates \(c_ {i+1}' = H(m, [r_i\cdot G + c_i\cdot K_i], [r_i\cdot H_p(K_i) + c_i\cdot\hat{K}])\) and checks that \(c_1 = c_1'\).

Finally, if the two different signatures (even with different rings) have been produced by the same signer then the both will have the same key images \(\hat{K}\).