Sri Lanka’s strong start allowed both Kusal Perera (82) and Tillakaratne Dilshan (84) to retire hurt before a single wicket fell.
There were 209 runs on the board when Ishant Sharma dismissed Mahela Jayawardene for 30 before Kumara Sangakkara went for 45 from an Amit Mishra
And when Dinesh Chandimal fell to Bhuvneshwar Kumar for 46 in the last over, India needed to score 334 runs in Birmingham.
MS Dhoni’s men were slow out of the blocks and lost Shikhar Dhawan (one), Murali Vijay (18) and Rohit Sharma (five) before Suresh Raina surrendered the fourth wicket to Sachithra Senanayake for 34.
But Kohli and Karthik led a remarkable revival with the former bringing up his century with two runs to follow a big six in the 37th over.
A boundary-hungry Karthik had scored 55 runs from just 46 balls by the start of the powerplay. Kohli was eventually caught at cover by Chandimal off a slow ball from Shaminda Eranga for 144.
But helped by the steady Dhoni (18 not out), Karthik drove one last four through point to finish on 106 not out and clinch victory for India with an over to spare.